我尝试使用gcc4.7
编译以下代码段vector<pair<int,char> > vp = {{1,'a'},{2,'b'}};
//For pair vector, it works like a charm.
vector<tuple<int,double,char> > vt = {{1,0.1,'a'},{2,4.2,'b'}};
但是,对于元组的向量,编译器会抱怨:
错误:从初始化列表转换为'std :: tuple'将使用显式构造函数'constexpr std :: tuple&lt; &gt; :: tuple(_UElements&amp;&amp; ...)[with _UElements = {int,double,char}; =无效_Elements = {int,double,char}]'
编译器溢出的错误信息对我来说是完全的胡言乱语,我不知道元组的构造函数是如何实现的,但我知道他们完全可以使用统一初始化(例如:{{1}因此,我想知道我遇到的问题只是编译器的TODO或它是C ++ 11标准定义的东西。
任何回复都将不胜感激!
答案 0 :(得分:11)
相关的std::tuple
构造函数为explicit
。这意味着你想要做的事情是不可能的,因为你想要使用的语法是根据复制初始化(禁止调用explicit
构造函数)来定义的。相反,std::tuple<int, float, char> { 1, 2.2, 'X' }
使用直接初始化。 std::pair
只有非explicit
构造函数。
使用直接初始化或标准元组工厂函数之一(例如std::make_tuple
)。
答案 1 :(得分:0)
这实际上是可行的,具有c ++ 11功能。
是的,initializer_list希望其所有元素属于同一类型。诀窍是我们可以创建一个包装类,它可以static_cast
到我们想要的所有类型。这很容易实现:
template <typename... tlist>
class MultiTypeWrapper {
};
template <typename H>
class MultiTypeWrapper<H> {
public:
MultiTypeWrapper() {}
MultiTypeWrapper(const H &value) : value_(value) {}
operator H () const {
return value_;
}
private:
H value_;
};
template <typename H, typename... T>
class MultiTypeWrapper<H, T...>
: public MultiTypeWrapper<T...> {
public:
MultiTypeWrapper() {}
MultiTypeWrapper(const H &value) : value_(value) {}
// If the current constructor does not match the type, pass to its ancestor.
template <typename C>
MultiTypeWrapper(const C &value) : MultiTypeWrapper<T...>(value) {}
operator H () const {
return value_;
}
private:
H value_;
};
使用隐式转换构造函数,我们可以将类似{1,2.5,'c',4}的内容传递给类型为MultiTypeWrapper的initializer_list(或vector,它隐式转换initializer_list)。这意味着我们无法编写像 这样的函数来接受这样的intializer_list作为参数:
template <typename... T>
std::tuple<T...> create_tuple(std::vector<unit_test::MultiTypeWrapper<T...> > init) {
....
}
我们使用另一个技巧将向量中的每个值转换为其原始类型(请注意,我们在MultiTypeWrapper
的定义中提供隐式转换)并将其分配给元组中的相应插槽。这就像模板参数的递归:
template <int ind, typename... T>
class helper {
public:
static void set_tuple(std::tuple<T...> &t, const std::vector<MultiTypeWrapper<T...> >& v) {
std::get<ind>(t) = static_cast<typename std::tuple_element<ind,std::tuple<T...> >::type>(v[ind]);
helper<(ind-1),T...>::set_tuple(t,v);
}
};
template <typename... T>
class helper<0, T...> {
public:
static void set_tuple(std::tuple<T...> &t, const std::vector<MultiTypeWrapper<T...> >& v) {
std::get<0>(t) = static_cast<typename std::tuple_element<0,std::tuple<T...> >::type>(v[0]);
}
};
template <typename... T>
std::tuple<T...> create_tuple(std::vector<unit_test::MultiTypeWrapper<T...> > init) {
std::tuple<T...> res;
helper<sizeof...(T)-1, T...>::set_tuple(res, init);
return res;
}
请注意,我们必须为set_tuple
创建辅助类,因为c ++不支持函数特化。现在,如果我们想测试代码:
auto t = create_tuple<int,double,std::string>({1,2.5,std::string("ABC")});
printf("%d %.2lf %s\n", std::get<0>(t), std::get<1>(t), std::get<2>(t).c_str());
输出结果为:
1 2.50 ABC
这是在我的桌面上用clang 3.2测试的
希望我的输入有所帮助:)
答案 2 :(得分:0)
讨厌吗?我之前也使用过对-在类似的情况下,惊讶于元组不支持此对,因为{}初始化语法节省了很多混乱。您可以使用 make_tuple 在容器中手动插入元素,因此:
vt.push_back(make_tuple(2,4.2,'b'));
应该工作