具有模板化构造函数以及复制和移动构造函数的类

mg8*_*g84 3 c++ templates constructor

这个问题是这个问题的后续:模板化类模板化构造函数的显式模板专业化另一个问题中给出的答案当然是正确的,但结果证明我并没有问我想问什么 - 所以这里是一个新问题:

考虑以下代码:

template<typename First, typename ... Rest> class var {
    public:

    var() {
        std::cout << "default" << std::endl;
    }

    var(const var& v) {
        std::cout << "copy" << std::endl;
    }

    var(var&& v) {
        std::cout << "move" << std::endl;
    }

    template<typename T>
    var(const T& t) {
        std::cout << "general lvalue" << std::endl;
    }


    template<typename T>
    var(T&& t) {
        std::cout << "general rvalue" << std::endl;
    }

};


int main()
{
    var<int> i0; // expect 'default' -> get 'default'

    var<int> i1(i0); // expect 'copy' -> get 'general rvalue'
    var<int> i2(std::move(i0)); // expect 'move' -> get 'move'

    std::string s("Hello");
    var<int> i3(s); // expect 'general lvalue' -> get 'general rvalue'
    var<int> i4(std::move(s)); // expect 'general rvalue' -> get 'general rvalue'
}
Run Code Online (Sandbox Code Playgroud)

我在主函数中写了我期望和想要调用的构造函数以及实际调用的构造函数。以下是我的问题:

1) 你能解释为什么程序不像我预期的那样运行吗?

2)如何让程序在获取 var 时调用 var 的复制和移动构造函数,否则如何调用模板化构造函数?

3)最后,我试图将两个模板化构造函数放在一个处理左值和右值的构造函数中,并使用 std::forward 将它们转发到另一个函数 - 这看起来像什么?

Jon*_*ely 5

1) 你能解释为什么程序不像我预期的那样运行吗?

在这一行:

var<int> i1(i0); // expect 'copy' -> get 'general rvalue'

var(T&&)构造被实例化以T与取代的var<int>&,即,产生与此签名构造:

var(var&);
Run Code Online (Sandbox Code Playgroud)

该构造函数比隐式复制构造函数更匹配,var(const var&)因为它i0是非常量的。

同样适用于:

var<int> i3(s); // expect 'general lvalue' -> get 'general rvalue'

s是非常量的,所以var(T&&)构造函数被实例化为T替换为std::string&,生成一个带有签名的构造函数:

var(std::string&);
Run Code Online (Sandbox Code Playgroud)

对于构造函数比其他构造函数模板更好的匹配的非常量参数,它产生:

var(const std::string&);
Run Code Online (Sandbox Code Playgroud)

您需要意识到var(T&&)构造函数不是“通用右值”构造函数,因为T&&可以匹配包括 lvalues 在内的任何类型。

有关更多详细信息,请参阅C++11 中的通用参考

2)如何让程序在获取 var 时调用 var 的复制和移动构造函数,否则如何调用模板化构造函数?

约束模板,使其不接受任何类型。

template<typename T>
  using Is_a_var = std::is_same<typename std::decay<T>::type, var>;

template<typename T>
  using Enable_if_not_a_var = typename std::enable_if<!Is_a_var<T>::value>::type;

template<typename T, typename Constraint = Enable_if_not_a_var<T>>
var(T&& t) {
    std::cout << "general value" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

我还会添加默认的复制/移动构造函数,以便让读者清楚你想要它们:

var(const var&) = default;
var(var&&) = default;
Run Code Online (Sandbox Code Playgroud)

3)最后,我试图将两个模板化构造函数放在一个处理左值和右值的构造函数中,并使用 std::forward 将它们转发到另一个函数 - 这看起来像什么?

别。该var(T&&)构造已同时接受右值左值。

用于std:forward<T>(t)将参数转发给其他函数:

template<typename T, typename Constraint = Enable_if_not_a_var<T>>
var(T&& t) : m_something(std::forward<T>(t)) {
    std::cout << "general value" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)