【问题标题】:Templated assignment operator failed template instantiation模板化赋值操作符模板实例化失败
【发布时间】:2014-12-09 14:24:39
【问题描述】:

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

#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&amp;&amp;应该绑定到const Base&amp;、Base&amp;&amp;、Base&amp;,以及const T&amp;T&amp;&amp;等。

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

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

【问题讨论】:

    标签: c++ templates c++11


    【解决方案1】:

    两个问题:

    1. 对于左值,forwarding-reference(以及模板类型参数T 本身)成为左值引用。在检查它是否是其他类型的子类之前,您应该decay键入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;
    }   
    

    【讨论】:

    • 我看到的所有enable_if 的例子都使用= 0 或= nullptr 成语(en.cppreference.com/w/cpp/types/enable_if),诚然我只是想复制它。你能解释一下吗?
    • @AndyG 是的,他们这样做了,但是他们在::type 之后加上了星号*,所以它变成了::type* = 0,并且当成功实例化时:void* = 0(或int* = 0,或int* = nullptr )。没有星号,你最终会得到 void = 0 这是无效的
    • 啊,我明白了。删除int 并使用::type* = nullptr 对我有用。非常感谢,这个问题一直困扰着我!
    • 请注意,void * 在技术上不是模板非类型参数的合法类型,尽管大多数编译器都支持它。
    猜你喜欢
    • 1970-01-01
    • 2021-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多