use*_*548 14 c++ uniform-initialization c++11
我有以下课程:
struct foo
{
std::size_t _size;
int* data;
public:
explicit foo(std::size_t s) : _size(s) { }
foo(std::size_t s, int v)
: _size(s)
{
data = new int[_size];
std::fill(&data[0], &data[0] + _size, v);
}
foo(std::initializer_list<int> d)
: _size(d.size())
{
data = new int[_size];
std::copy(d.begin(), d.end(), &data[0]);
}
~foo() { delete[] data; }
std::size_t size() const { return _size; }
};
Run Code Online (Sandbox Code Playgroud)
我想像这样向它转发论据:
template <typename... Args>
auto forward_args(Args&&... args)
{
return foo{std::forward<Args>(args)...}.size();
//--------^---------------------------^
}
std::cout << forward_args(1, 2) << " " << forward_args(1) << " "
<< forward_args(2) << "\n";
Run Code Online (Sandbox Code Playgroud)
如果我{}用()输出替换1 1 2而不是2 1 1.
哪个对我的班级最有意义?
{}vs.的使用()决定了调用哪个构造函数。
他们{}会调用该表格foo(std::initializer_list<int> d),您就会得到您期望的结果。
将()调用explicit foo(std::size_t s)and foo(std::size_t s, int v),并且在所有情况下,第一个元素是大小,因此给定参数,您将得到您所看到的结果。
支持哪种形式取决于您希望该forward_args方法支持什么语义。如果您希望参数“按原样”传递,则应()使用(在这种情况下,用户需要提供 aninitialiser_list作为参数)。
可能(可能)您希望采用的形式()如下;
template <typename... Args>
auto forward_args(Args&&... args)
{
return foo(std::forward<Args>(args)...).size();
//--------^---------------------------^
}
int main()
{
std::cout << forward_args(std::initializer_list<int>{1, 2}) << " "
<< forward_args(std::initializer_list<int>{3}) << " "
<< forward_args(std::initializer_list<int>{4}) << "\n";
}
Run Code Online (Sandbox Code Playgroud)
边注; 上的cppreference 页面有initializer_list一个很好的例子来说明这种行为。
如果需要(即支持forward_args({1,2})),您可以为 提供重载initializer_list;
template <class Arg>
auto forward_args(std::initializer_list<Arg> arg)
{
return foo(std::move(arg)).size();
}
Run Code Online (Sandbox Code Playgroud)
如上所述:考虑到initializer_list,类构造函数最终是混乱的根源,这在对象构造过程中就出现了。foo(1,2)和之间有区别foo{1,2};后者调用initializer_list构造函数的形式。解决此问题的一种技术是使用“标记”来区分“正常”构造函数形式和形式initializer_list。