将可变参数模板转发给几个类成员

时间:2013-11-27 23:20:36

标签: c++ templates c++11 perfect-forwarding

以下是否安全?在初始化第一个类成员后,std::string是不是move d?打印好了,但我不确定。

template <typename T>
class Test
{
public:

    template <typename... Args>
    Test(Args&&... args)
    :  m_one(new T(std::forward<Args>(args)...)),
       m_two(new T(std::forward<Args>(args)...))    // <- Here
    {
    }

private:
    std::unique_ptr<T> m_one;
    std::unique_ptr<T> m_two;
};


class C
{ 
public:

    C(int a, int b, const std::string& c)
    :  m_a(a),
       m_b(b),
       m_c(c)
    {
        std::cout << "ctor a=" << m_a << ", b=" << m_b << ", c=" << m_c << "\n";
    }

    int m_a;
    int m_b;
    std::string m_c;
};


int main()
{
     Test<C> t(1, 2, "3");
}

我想这是可以的,因为C的第三个ctor参数是const std::string&,但是如何在一个采用r值ref的类中阻止完美转发,例如C(int, int, std::string&&)那么m_two将不会收到与m_one相同的ctor args?

将测试的ctor更改为

   template <typename... Args>
   Test(Args&... args)

无法编译。也不会从std::forward<Args>(args)...m_one ctors中删除m_two

1 个答案:

答案 0 :(得分:7)

你想要使用这样的东西:

#include <memory>
#include <string>
#include <iostream>
#include <utility>

template <typename T>
class Test
{
public:

    template <typename... Args>
    Test(Args&&... args)
    :  m_one(new T(args...)),                    // avoid moving the first time
       m_two(new T(std::forward<Args>(args)...)) // but allowing moving the last time
    {
    }

private:
    std::unique_ptr<T> m_one;
    std::unique_ptr<T> m_two;
};


class C
{
public:

    C(int a, int b, std::string c) // rule of thumb -- if you are going to copy an argument
                                   // anyway, pass it by value.
    :  m_a(a),
       m_b(b),
       m_c(std::move(c)) // you can safely move here since it is the last use. 
    {
        std::cout << "ctor a=" << m_a << ", b=" << m_b << ", c=" << m_c << "\n";
    }

    int m_a;
    int m_b;
    std::string m_c;
};

对于m_one,参数使用左值引用,因此不会发生移动。对于m_twostd::forward将根据需要使用右值引用。将std::string参数按C按值并使用std::move使其适用于任何一种情况。如果传递左值引用,则参数将被复制构造,但是如果传递右值引用,则参数将被移动构造。在任何一种情况下,您都可以将参数移到m_c成员中以提高效率。