通过模板化的朋友类完美转发到私有类构造函数

时间:2017-03-26 22:07:30

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

我正在探索friend关键字与变量模板,完美转发和私有构造函数的使用。我觉得我错过了所有这些基本的东西,因为以下简单的例子不会编译。

我希望Test_Manager<Test_Class>::Process是构建Test_Class类型对象的唯一方法(Process最终会做更多但这是一个简单的例子)。我还希望Test_Manager能够管理&#39;这种方式的各种类,因此类类型的参数t_Symbol和处理各种构造函数的可变参数...t_Args

// Test.cpp
#include <string>

template<typename t_Symbol>
struct Test_Manager
{
    template<typename... t_Args>
    static t_Symbol Process(const t_Args&... i_Args)
    {
        const t_Symbol New_Symbol(std::forward<t_Args>(i_Args)...); // error C2665

        return New_Symbol;
    }
};

class Test_Class
{
    private:

        friend Test_Manager<Test_Class>;

        Test_Class() {};
        Test_Class(const std::string& i_Text) : m_Text(i_Text) {};

        const std::string m_Text;
};

void Test_Function()
{
    std::string text = "hello_world";

    Test_Class t = Test_Manager<Test_Class>::Process(text);
}

但是,在Visual Studio 2015 Update 3中,我收到以下错误(在上面标记的行):error C2665: 'std::forward': none of the 2 overloads could convert all the argument types。我搞砸了什么?我觉得这应该有效。

2 个答案:

答案 0 :(得分:3)

  

我在这里搞砸了什么?

是的,你是。在下面的代码中:

template<typename... t_Args>
static t_Symbol Process(const t_Args&... i_Args){
    const t_Symbol New_Symbol(std::forward<t_Args>(i_Args)...);
    ...
}

上述问题是,i_Args将获得const资格,但您告诉std::forward std::forward<t_Arg>您将发送t_Arg类型,但不会; t具有const资格。

因此,基本上,std::forward<t_Args>(i_Arg)的问题在于类型 t_Args,不会带有隐式const,但< em> Argument i_Arg,有const

您应该在转发引用时使用std::forward。当您这样做时,t_Arg将隐式携带必要的 cv 资格,该资格将与i_Arg

cv 资格相匹配

您想将其更改为:

template<typename... t_Args>
static t_Symbol Process(t_Args&&... i_Args){
    ...
}

编辑,根据Guillaume Racicot的评论:

当您尝试值移动到Process时,例如:

Test_Manager<Test_Class>::Process(std::move(text));

Test_Class的构造函数将击败std::forward,因为它仍然会按照副本进行复制。

Test_Class(const std::string& i_Text) : m_Text(i_Text) {};

但是,当构造函数定义为:

Test_Class(std::string i_Text) : m_Text(std::move(i_Text)) {};

不会复制,只会移动。

答案 1 :(得分:1)

std::forward适用于转发引用(或通用引用),它是T&&函数参数,其中T是模板参数。完美转发看起来像:

template<typename... t_Args>
static t_Symbol Process(t_Args&&... i_Args)
{
    t_Symbol New_Symbol(std::forward<t_Args>(i_Args)...);

    return New_Symbol;
}

如果您希望Process仅使用const左值,那可以,但不要使用std::forward

template<typename... t_Args>
static t_Symbol Process(const t_Args&... i_Args)
{
    t_Symbol New_Symbol(i_Args...);

    return New_Symbol;
}