模板化赋值运算符模板实例化失败

时间:2014-12-09 14:24:39

标签: c++ templates c++11

我正在尝试构建一个模板化的基类,允许分配给它的任何模板类型,如:

#include <type_traits>
#include <utility>

template<typename T1, typename... Types>
class Base
{
    public:
    //assignment to base or derived class
    template<typename T, typename std::enable_if<std::is_base_of<Base<T1, Types...>, T>::value>::type = 0>
    Base& operator=(T&& other)
    {
        if (this != &other)
            a = other.a;
        return *this;
    }

    //assignment to other type contained in <T1, Types...>
    template<typename T, typename std::enable_if<!std::is_base_of<Base<T1, Types...>, T>::value>::type = 0>
    Base& operator=(T&& other)
    {
        // do some stuff
        return *this;
    }


    private:
    int a;
};

正如您所看到的,我正在尝试使用std::enable_if将分配区分为Base(移动或复制),并通过包装std::is_base_of来分配类型。我的印象是T&&应该绑定到const Base&Base&&Base&以及const T& T&&等。< / p>

当我尝试通过简单地将参数转发到基类来创建支持赋值的派生类时,就会出现问题:

class Derived : public Base<int, double>
{
    public:
    // similar pattern here, but call base class' operators
    // for both copy/move assignment
    // as well as assignment to int or double
    template<typename T>
    Derived& operator=(T&& other)
    {
        Base<int, double>::operator=(std::forward<T>(other));
        return *this;
    }
};

一旦我尝试做我认为应该是有效的赋值,编译器就会告诉我它没有执行模板推导/替换。

int main() {
    Derived foo;
    int a = 4;
    foo = a;
    return 0;
}

我在这里做错了什么?请放轻松我。

Live example

1 个答案:

答案 0 :(得分:5)

两个问题:

  1. 对于左值, forwarding-reference (以及模板类型参数T本身)成为左值参考。在检查它是否是其他类型的子类之前,您应衰减类型T

  2. 您以错误的方式使用std::enable_if;如果您想使用::type = 0语法,则需要使用除默认void之外的其他类型。

  3. 话虽如此,您的std::enable_if语法应如下所示:

    typename std::enable_if<std::is_base_of<Base<T1, Types...>
                                           , typename std::decay<T>::type // decay of T
                                           >::value
                          , int>::type = 0 // int as a second template argument
    

    完整示例:

    template<typename T, typename std::enable_if<std::is_base_of<Base<T1, Types...>, typename std::decay<T>::type>::value, int>::type = 0>
    Base& operator=(T&& other)
    {
        if (this != &other)
            a = other.a;
        return *this;
    }
    
    //assignment to other type contained in <T1, Types...>
    template<typename T, typename std::enable_if<!std::is_base_of<Base<T1, Types...>, typename std::decay<T>::type>::value, int>::type = 0>
    Base& operator=(T&& other)
    {
        // do some stuff
        return *this;
    }