【问题标题】:Class with templated constructor as well as copy and move constructor具有模板化构造函数以及复制和移动构造函数的类
【发布时间】:2014-02-25 19:21:51
【问题描述】:

这个问题是对这个问题的后续:Explicit template specialization for templated constructor of templated class 另一个问题中给出的答案当然是正确的,但事实证明我并没有完全问我想问的问题 - 所以这里有一个新问题:

考虑以下代码:

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'
}

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

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

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

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

【问题讨论】:

    标签: c++ templates constructor


    【解决方案1】:

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

    在这一行:

    var&lt;int&gt; i1(i0); // expect 'copy' -&gt; get 'general rvalue'

    var(T&amp;&amp;) 构造函数用T 替换为var&lt;int&gt;&amp; 进行实例化,即生成具有此签名的构造函数:

    var(var&);
    

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

    同样适用于:

    var&lt;int&gt; i3(s); // expect 'general lvalue' -&gt; get 'general rvalue'

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

    var(std::string&);
    

    对于非 const 参数,构造函数比其他构造函数模板更匹配,生成:

    var(const std::string&);
    

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

    更多详情请见Universal References in 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;
    }
    

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

    var(const var&) = default;
    var(var&&) = default;
    

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

    不要。 var(T&amp;&amp;) 构造函数已经接受右值 左值。

    使用std:forward&lt;T&gt;(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;
    }
    

    【讨论】:

    • 很棒且非常详细的答案。帮了我很多!谢谢!
    猜你喜欢
    • 2011-05-24
    • 2016-09-12
    • 2019-08-11
    • 2016-09-02
    • 1970-01-01
    • 2020-11-16
    • 2016-03-22
    • 1970-01-01
    • 2023-03-20
    相关资源
    最近更新 更多