Conditional enable an alternative assignment operator

夙愿已清 提交于 2019-12-21 15:06:08

问题


I'm trying to conditionally instantiate an extra assignment operator. The code below works fine in clang, but not in gcc 4.7.

The problem I'm having seems very similar the the question asked here: std::enable_if to conditionally compile a member function

The following illustrates the problem I'm having:

#include <type_traits>

template<typename T>
struct StrangerTypeRules;

template<typename T>
struct X;

template< >
struct StrangerTypeRules < unsigned > {
    typedef unsigned type;
};

template< >
struct StrangerTypeRules < bool > {
    typedef X<bool> type;
};

template<typename T>
struct X {
    // In the non-trivial version of my code, I can not use the
    // default assignment operator, therefor I need to define this one
    X& operator=( const X<T>& rhs ) {
        return *this;
    }

    // Alternative assignment oprtator, must only exists if it is
    // different from the assignment operator above
    template<typename =
        typename std::enable_if<
            ( !std::is_same<
                X<T>,
                typename StrangerTypeRules<T>::type
            >::value ),
            X<T>
        >::type
    >
    X<T> & operator=( const typename StrangerTypeRules <T>::type& rhs ) {
        return *this;
    }
};

int main(int argc, const char *argv[])
{
    X<unsigned> x1, x2;

    x1 = 4;
    x2 = x1;

    X<bool> x3, x4; // compile error in gcc 4.7 with -std=c++11
    //x3 = x4;

    return 0;
}

Can this be done in a way which satisfies both clang and gcc 4.7? If so, how?

Compilations error when using gcc:

test.cxx: In instantiation of ‘struct X<bool>’:
test.cxx:52:13:   required from here
test.cxx:38:12: error: no type named ‘type’ in ‘struct std::enable_if<false, X<bool> >’

回答1:


You need to make the enable_if dependent on a template parameter. As it is now, it is only dependent on the outer template parameter within the template definition. But if you instantiate a class from the outer template, then your assignment operator template that is instantiated into that class is not dependent on a template parameter anymore because T will have been substituted already.

Just introduce a dummy parameter equal to T

template<typename T1 = T, typename =
    typename std::enable_if<
        ( !std::is_same<
            X<T1>,
            typename StrangerTypeRules<T1>::type
        >::value ),
        X<T1>
    >::type
>
X<T1> & operator=( const typename StrangerTypeRules <T1>::type& rhs ) {
    return *this;
}

Using T1 in just one of theplaces within the enable_if<...> template arguments would suffice already, because that already makes the enable_if dependent.

However it is not the call to your operator= that was previously illformed but the declaration of it, which conflicts with the copy-assignment operator, so the enable_if has little utility here. Just replace your code by

template<typename T1 = T>
X<T1> & operator=( const typename StrangerTypeRules <T1>::type& rhs ) {
    return *this;
}

Since this operator= is a template, it will not conflict with the non-template overload. And also because it is a template, when you call it the compiler will prefer the non-template if T is X<T>.



来源:https://stackoverflow.com/questions/9889101/conditional-enable-an-alternative-assignment-operator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!