enable_if и взаимоисключающие методы

Я не могу понять, почему следующий код не работает. компилятор (gcc), похоже, создает экземпляры обоих методов, и, очевидно, целое число либо со знаком, либо без знака, поэтому один всегда терпит неудачу. Я хотя enable_if был здесь, чтобы избежать этого.

В: почему возникает ошибка компиляции и как ее избежать?

using namespace boost; // or std as you want

template<typename T>
struct test {
    // if signed
    template< typename enable_if
                        < is_signed<T>
                        , int
                        >:: type = 0
            >
    test &operator<<=(int value)
    {}

    // if unsigned
    template< typename enable_if
                        < is_unsigned<T>
                        , int
                        >:: type = 0
            > 
    test &operator<<=(int value)
    {}
};

void foo()
{
    test<int> x;
    x << 1;            // COMPILE ERROR no type named 'type' in struct enable_if<unsigned> etc.
    test<unsigned> y;
    y << 1;            // COMPILE ERROR no type named 'type' in struct enable_if<int> etc.
}

person syp    schedule 08.12.2014    source источник
comment
Определите, что это не работает. Что случается? Чем это отличается от того, что вы хотели? Мы не можем волшебным образом угадать ваши намерения исключительно по фрагменту кода, который, по вашему собственному признанию, не представляет этой цели.   -  person Lightness Races in Orbit    schedule 08.12.2014
comment
добавлено... но избыточно с "кажется, реализует оба метода..."   -  person syp    schedule 09.12.2014
comment
Совсем не лишнее, нет. Мы ученые. Мы ценим точность, конкретность и данные. Кажется, что реализация обоих методов не является ни одной из этих вещей!   -  person Lightness Races in Orbit    schedule 09.12.2014


Ответы (1)


SFINAE применим только в непосредственном контексте (SFINAE = SFIICINAE, Ошибка замены в Непосредственный контекст не является ошибкой):

§14.8.2 [temp.deduct]/p8:

Только недопустимые типы и выражения в непосредственном контексте типа функции и ее типов параметров шаблона могут привести к ошибке вывода.

Подстановка параметров шаблона класса в объявлении функции-члена не является непосредственным контекстом и приводит к серьезной ошибке в случае сбоя.

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

template <typename U = T, typename std::enable_if<std::is_signed<U>{}, int>::type = 0>
test &operator<<=(int value)
{ return *this; }

template <typename U = T, typename std::enable_if<std::is_unsigned<U>{}, int>::type = 0>
test &operator<<=(int value)
{ return *this; }
person Piotr Skotnicki    schedule 08.12.2014