Условно включить альтернативный оператор присваивания - PullRequest
5 голосов
/ 27 марта 2012

Я пытаюсь создать условный экземпляр дополнительного оператора присваивания. Приведенный ниже код отлично работает в clang, но не в gcc 4.7.

Проблема, с которой я столкнулся, кажется очень похожей на вопрос, заданный здесь: std :: enable_if для условной компиляции функции-члена

Следующая проблема иллюстрирует мою проблему:

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

Может ли это быть сделано способом, который удовлетворяет как clang, так и gcc 4.7? Если да, то как?

Ошибка компиляции при использовании 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 Ответ

2 голосов
/ 28 марта 2012

Необходимо сделать enable_if зависимым от параметра шаблона. Как и сейчас, он зависит только от внешнего параметра шаблона в определении шаблона. Но если вы создаете экземпляр класса из внешнего шаблона, тогда ваш шаблон оператора присваивания, который создается в этом классе, больше не зависит от параметра шаблона, поскольку T уже будет подставлено.

Просто введите фиктивный параметр, равный 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;
}

Использование T1 только в одном из мест в аргументах шаблона enable_if<...> уже будет достаточным, потому что это уже делает enable_if зависимым.

Однако это не вызов вашего operator=, который был ранее не информирован, а его объявление , которое конфликтует с оператором копирования-назначения, поэтому enable_if здесь мало полезного Просто замените свой код на

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

Поскольку этот operator= является шаблоном, он не будет конфликтовать с не шаблонной перегрузкой. А также потому, что это шаблон, когда вы его называете, компилятор предпочтет не шаблон, если T равно X<T>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...