【问题标题】:Forward variadic template args to several class members将可变参数模板参数转发给几个类成员
【发布时间】:2013-11-27 23:20:35
【问题描述】:

以下安全吗?第一个类成员初始化后std::string 不是moved 吗?打印出来没问题,但我不确定。

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&amp;,但是我如何防止在采用 r 值 ref 的类中完美转发,例如C(int, int, std::string&amp;&amp;) as then m_two 将不会收到与 m_one 相同的 ctor args?

将 Test 的 ctor 更改为

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

不编译。也不会从 m_onem_two ctors 中删除 std::forward&lt;Args&gt;(args)...

【问题讨论】:

  • 初始化m_one的时候最好不要使用std::forward
  • 无法编译:main.cpp:31: 错误:无法将 'std::basic_string' 左值绑定到 'std::string&& {aka std::basic_string&& }'
  • @James:你一定做错了什么。沃恩的意思是this。经验法则是:当多次完美转发同一个参数时,不要。无需完美转发,只需将其传递,并让目标制作副本(如果他们愿意)。如果你想转发,只在最后一次(在这种情况下m_two的初始化)。
  • @Xeo,是的,你是对的

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


【解决方案1】:

你会想要使用这样的东西:

#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 成员中以提高效率。

【讨论】:

    猜你喜欢
    • 2015-11-08
    • 1970-01-01
    • 2015-03-12
    • 2021-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多