比如说,我有一个封装在名为 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}};
error: could not convert '{{1, 2}, {1, 2}}' from brace-enclosed initializer list to '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}};
会存活下来,但会失去一些参数的灵 active 。
经过一番搜索,我终于意识到这可能违反了模板参数推导的规则,
Non-deduced contexts
6) The parameter P, whose A is a braced-init-list, but P is not std::initializer_list, a reference to one (possibly cv-qualified), or a reference to an array:
但我还在徘徊 是否还有办法实现这个想法?如何实现?
最佳答案
问题是 {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}}};
。)
关于c++ - 在 C++11 中,我可以为非聚合类型实现类似构造函数的聚合类型初始化吗?如何实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57252228/