说,我有一个一维数组,封装在名为stA
的类中
class stA
{
public:
template<typename ... T>
stA(T ... t):
data_{t...}
{}
private:
int data_[2];
};
通过利用可变模板,我可以成功实现这一想法。
stA a = {1, 2};
但是,当我尝试将此技巧引入名为stB
的二维类时,
class stB
{
public:
template<typename ... T>
stB(T ... t):
data_{t...}
{}
private:
stA data_[2];
};
把戏失败了。
stB b = {{1, 2}, {1, 2}};
错误:无法从括号括起来的内容中转换'{{1,2},{1,2}}' 初始化程序列表为“ stB” stB b = {{1,2},{1,2}};
这在开始时让我很困惑。
因为如果stB::Ctor
中的 template-argument-deduction 产生T = const stA &
,那么Ctor
将会变成这样,
stB(const stA & a, const stA & b):
data_{a, b}
{}
当然还有stB b = {{1, 2}, {1, 2}};
可以幸免,但会失去论点的灵活性。
完成搜索后,我终于意识到这可能违反了模板参数推导,
非推论上下文
6)参数P,其A是一个括号初始化列表,但P不是 std :: initializer_list,一个引用(可能是cv限定),或 对数组的引用:
但是我还在徘徊 还有没有办法使这个想法发生以及如何发生?
答案 0 :(得分:4)
问题在于{1, 2}
不是表达式,只能推导表达式。
选项1:使用聚合初始化。将data_
成员设为公开,并且聚合初始化使您可以初始化元素。缺点:控制力很小。
选项2:使用initializer_list
。如:
class stA {
public:
stA(std::initializer_list<int> init):
data_{init.begin()[0], init.begin()[1]}
{
assert(init.size() == 2);
}
private:
int data_[2];
};
class stB {
public:
stB(std::initializer_list<std::initializer_list<int>> init):
data_{init.begin()[0], init.begin()[1]}
{
assert(init.size() == 2);
}
private:
stA data_[2];
};
缺点:大小信息在编译时丢失。
选项3:将聚合类型用作构造函数参数。
class stA {
public:
stA(const int (&arr)[2]):
data_{arr[0], arr[1]}
{
}
private:
int data_[2];
};
class stB {
public:
stB(const int (&arr)[2][2]):
data_{arr[0], arr[1]}
{
}
private:
stA data_[2];
};
(这需要一对额外的花括号,例如stB b = {{{1, 2}, {3, 4}}};
。)