简体   繁体   English

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

[英]templated constructor vs. templated copy constructor

I have a class with a templated constructor for implicit move conversion, however this constructor should NOT be used for the class (which should only be copy constructible). 我有一个带有模板化构造函数的类,用于隐式移动转换,但是这个构造函数不应该用于类(它应该只是可复制的构造)。 However, the compiler always tries to use the templated constructor instead of the regular copy constructor. 但是,编译器总是尝试使用模板化构造函数而不是常规复制构造函数。

eg With this i get the follow compiler errors, link . 例如,我得到以下编译器错误, 链接 (you can just copy paste this code if you want to try it) (如果你想试试,可以复制粘贴这段代码)

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_;
};

Any one got an idea how to solve this properly? 任何人都知道如何妥善解决这个问题?

Okay, here is my complete overhaul of my_class : 好的,这是我对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_;
};

As suggested by others, this works for lvalue and rvalue references by using std::forward instead of std::move . 正如其他人所建议的那样,这适用于使用std::forward而不是std::move左值和右值引用。 The remove_reference is necessary because for lvalue references, T is a reference, and derived& does not derive from base , but derived does (note the reference). remove_reference是必要的,因为对于左值引用, T是一个引用, derived&不是从base派生的,而是derived (请注意引用)。

This can never work: 这永远不会奏效:

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)

The reason is that you only use T in non-deduced contexts. 原因是您只在非推导的上下文中使用T Plainly speaking, the compiler cannot deduce T if the argument it should have deduce it from has the form Anything<T>::type . 简单来说,编译器不能推断T如果它应该推导出的参数具有Anything<T>::type

So, if you want to use enable_if on assignment operator, you put it in the return value: 因此,如果要在赋值运算符上使用enable_if ,则将其放在返回值中:

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

in case of the conversion (should work for move, too) constructor, you add a dummy parameter with default value: 如果转换(也应该适用于move)构造函数,则添加一个带有默认值的虚拟参数:

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

FredOverflow already gave you the correct assignment operator. FredOverflow已经为您提供了正确的赋值运算符。

BTW you needn't restrict it to rvalue-references, if you use std::forward instead of std::move . 顺便说一句,如果使用std::forward而不是std::move ,则无需将其限制为rvalue-references。 See here . 看到这里 That would give you (copy&paste from FredOverflow): 这会给你(从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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM