转发参数时我应该使用()还是{}?

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.

哪个对我的班级最有意义?

Nia*_*all 2

{}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。