提问人:Miroslav Krajcir 提问时间:11/5/2023 最后编辑:wohlstadMiroslav Krajcir 更新时间:11/5/2023 访问量:128
C++ 如何从可变参数包初始化向量?
c++ how to initialize vector from variadic pack?
问:
我有一个模板化的存储值。s 或 s 没有问题,但值无法编译。编译器似乎假设我想用 s 而不是 values 初始化。我该如何解决这个问题?Container
vector
string
int
size_t
vector
int
size_t
#include <iostream>
#include <vector>
template <class ValueType>
class Container {
public:
template <typename... ValueTypes>
Container(ValueTypes&&... values) :
currentIndex(0),
values{ std::forward<ValueTypes>(values)... }
{}
const ValueType operator()() const {
return values[currentIndex];
}
protected:
size_t currentIndex;
std::vector<ValueType> values;
};
int main() {
Container<std::string> container1("10", "20", "30"); // ok
Container<int> container2(10, 20, 30); // ok
Container<size_t> container3(10, 20, 30); // compile error, assumed ints!
}
答:
3赞
wohlstad
11/5/2023
#1
10
,并且确实是文字,因此缩小转换错误/警告是意料之中的。20
30
int
您可以使用(或)后缀使它们符合(无符号):u
ULL
size_t
Container<size_t> container3(10u, 20u, 30u);
评论
1赞
Miroslav Krajcir
11/5/2023
谢谢。但是std::vector<size_t> v{10, 20, 30}怎么可能没有问题呢?编译器假设此处不带任何后缀size_t...
1赞
Jesper Juhl
11/5/2023
另一种选择是 - 我同意后缀是更好的选择,但只是提到替代方案。size_t(10)
u
4赞
Pepijn Kramer
11/5/2023
#2
这是两种可供选择的方法(第二种方法更类型安全,但需要稍微不同的语法才能使用)。
#include <iostream>
#include <vector>
#include <type_traits>
template <class type_t>
class Container {
public:
// Constructor 1
template <typename... args_t>
Container(args_t&&... args) :
m_currentIndex{}
{
// pre alocate memory to avoid resizing
m_values.reserve(sizeof...(args_t));
// use a fold expression to put all values in the vector
(m_values.emplace_back(std::forward<args_t>(args)),...);
}
// Constructor 2, more typesafe
template<std::size_t N>
Container(const type_t (&values)[N]) :
m_values{std::begin(values),std::end(values)}
{
}
// return a const& here so you avoid a copy
const type_t& operator()() const
{
return m_values[m_currentIndex];
}
protected:
size_t m_currentIndex;
std::vector<type_t> m_values;
};
int main()
{
// Constructor 1
Container<std::string> container1{"10", "20", "30"}; // ok
Container<int> container2{10, 20, 30}; // ok
Container<size_t> container3{10, 20, 30}; // ok
// Constructor 2
Container<std::string> container4{{"10", "20", "30"}}; // ok
Container<int> container5{{10, 20, 30}}; // ok
Container<size_t> container6{{10, 20, 30}}; // ok
}
3赞
user12002570
11/5/2023
#3
问题是这不是一个常量表达式(因为它是一个函数参数),所以从 to 的转换是一个缩小的转换。values
values
size_t
这可以从 dcl.init.list#7 中看出,其中指出:
缩小转换是从整数类型或无作用域枚举类型到整数类型的隐式转换,该类型不能表示原始类型的所有值,除非源是常量表达式,其整数升级后的值将适合目标类型。
(强调我的)
基本上,这与为什么会起作用但不起作用的原因相同。同样,会起作用。std::vector<size_t> v{10, 20, 30}
int i = 0; std::vector<size_t> v{i, 20, 30};
const int i = 0; std::vector<size_t> v{i, 20, 30};
std::vector<size_t> v{10, 20, 30}; //ok because 10, 20 and 30 all are constant expressions
int i = 0; //i is not a constant expression
std::vector<size_t> v{i, 20, 30}; //not ok because i is not a constant expression and so narrowing conversion
const int j= 0; //j is a constant expression
std::vector<size_t> v{j, 20, 30}; //ok because j is a constant expression
解决此问题的一种方法是为每个文字显式写入后缀。U
Container<size_t> container3(10U, 20U, 30U);
3赞
康桓瑋
11/5/2023
#4
您可以转发构造实际的 ,以便通过ValueTypes
ValueType
std::vector<ValueType>
std::initializer_list<ValueType>
template <typename... ValueTypes>
Container(ValueTypes&&... values) :
currentIndex(0),
values{ ValueType(std::forward<ValueTypes>(values))... }
{}
评论
Container<size_t> container3(10ULL, 20ULL, 30ULL);