模板化构造函数与模板化复制构造函数

时间:2010-12-11 22:42:11

标签: c++ templates constructor c++11 copy-constructor

我有一个带有模板化构造函数的类,用于隐式移动转换,但是这个构造函数不应该用于类(它应该只是可复制的构造)。但是,编译器总是尝试使用模板化构造函数而不是常规复制构造函数。

e.g。有了这个,我得到了以下编译器错误,link。 (如果你想尝试,你可以复制粘贴这段代码)

struct implementation{};
class my_class
{
 my_class(my_class&&); // delete move-constructor... OUCH... COMPILER ERROR
public:
 my_class(){}
 my_class(const my_class& other) : impl_(other.impl_){}

 template<typename T>
 my_class(T&& impl) : impl_(std::make_shared<T>(std::move(impl))){} // Still tries to use this...

private:
 std::shared_ptr<implementation> impl_;
};

class other_class
{
public:
 my_class foo()
 { 
       return instance_; // Wants to use move-constructor???
 }
private:
 my_class instance_;
};

任何人都知道如何妥善解决这个问题?

2 个答案:

答案 0 :(得分:4)

好的,这是我对my_class的全面改革:

class my_class
{
public:
    my_class() {}
    my_class(my_class&& that) : impl_(std::move(that.impl_)) {}

    template <typename T> my_class(T&& impl,
    typename std::enable_if<
        std::is_base_of<
            implementation,
            typename std::remove_reference<T>::type
        >::value,
        void
    >::type* dummy = 0
    ) : impl_(std::make_shared<T>(std::forward<T>(impl))) {}

    template <typename T>
    typename std::enable_if<
        std::is_base_of<
            implementation,
            typename std::remove_reference<T>::type
        >::value,
        my_class&
    >::type
    operator=(T&& impl)
    {
        std::make_shared<implementation>(std::forward<T>(impl)).swap(impl_);
        return *this;
    }

private:
    std::shared_ptr<implementation> impl_;
};

正如其他人所建议的那样,这适用于使用std::forward代替std::move的左值和右值引用。 remove_reference是必要的,因为对于左值引用,T是引用,而derived&不是来自base,而是derived({注释引用)

答案 1 :(得分:2)

这永远不会奏效:

template<typename T>
my_class(typename std::enable_if<std::is_base_of<implementation, derived_1>::value, T&&>::type impl) : impl_(std::make_shared<T>(std::move(impl)))  {}

template <typename T> 
my_class& operator= (typename std::enable_if<std::is_rvalue_reference<T&&>::value && !std::is_same<T, my_class>::value, T&&>::type impl)

原因是您只在非推断的上下文中使用T。简单来说,编译器不能推导出T,如果它应该从中推导出它的形式为Anything<T>::type

所以,如果你想在赋值运算符上使用enable_if,你可以把它放在返回值中:

template <class T>
typename enable_if<..., T&>::type operator=(const T&);

如果转换(也适用于移动)构造函数,则添加一个带默认值的虚拟参数:

template <class T>
MyClass(const T&, typename enable_if<..., void>::type* =0);

FredOverflow已经为您提供了正确的赋值运算符。

顺便说一下,如果您使用std::forward而不是std::move,则无需将其限制为右值参考。见here。这会给你(从FredOverflow复制和粘贴):

template <typename T>
typename std::enable_if<std::is_base_of<implementation, T>::value, my_class&>::type
operator=(T&& impl)
{
    std::make_shared<implementation>(std::forward<T>(impl)).swap(impl_);
    return *this;
}