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

Templated assignment operator failed template instantiation

本文关键字:失败 实例化 赋值运算符      更新时间:2023-10-16

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

#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&&等。

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

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

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

现场示例

两个问题:

  1. 对于左值,转发引用(以及模板类型参数T本身)将成为左值引用。在检查类型T是否是其他类型的子类之前,您应该衰减它。

  2. 你以错误的方式使用std::enable_if;如果你想使用::type = 0语法,那么它需要一些其他类型,而不是默认的void

话虽如此,您的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;
}