Шаблоны C ++ и операторы перегрузки - PullRequest
0 голосов
/ 08 декабря 2011

Я столкнулся с каким-то странным поведением. Я не уверен, должно ли это работать или нет. Обратите внимание, что я не пытаюсь заставить это работать, я скорее обеспокоен теоретической стороной. Я использую Visual C ++ 2010. Соблюдайте следующий код

template <class T_>
ostream &operator <<(std::ostream &out, 
        typename SequenceCheckResult<T_>::directiontype const &direction) {

    switch(direction) {
    case SequenceCheckResult<T_>::None:
        out<<"none o";
        break;
    case SequenceCheckResult<T_>::Horizontal:
        out<<"horizontal _";
        break;
    case SequenceCheckResult<T_>::Vertical:
        out<<"vertical |";
        break;
    case SequenceCheckResult<T_>::ForwardDiagonal:
        out<<"forward diagonal \\";
        break;
    case SequenceCheckResult<T_>::BackwardDiagonal:
        out<<"backward diagonal /";
        break;
    }

    return out;
}

Очевидно, что шаблонный класс SequenceCheckResult содержит перечисление с именем directiontype. Теперь приведенный выше код не получает экземпляры и печатается целочисленное значение переменной. Даже если я предоставлю специализацию, это все еще не работает. Если я создаю следующую функцию, она используется и печатается текстовое значение. Обратите внимание, что следующий код и специализация int вышеуказанной функции отличаются только на template<> строку и <int> после operator <<.

ostream &operator << (std::ostream &out, 
         SequenceCheckResult<int>::directiontype const &direction) {

    switch(direction) {
    case SequenceCheckResult<int>::None:
        out<<"none o";
        break;
    case SequenceCheckResult<int>::Horizontal:
        out<<"horizontal _";
        break;
    case SequenceCheckResult<int>::Vertical:
        out<<"vertical |";
        break;
    case SequenceCheckResult<int>::ForwardDiagonal:
        out<<"forward diagonal \\";
        break;
    case SequenceCheckResult<int>::BackwardDiagonal:
        out<<"backward diagonal /";
        break;
    }

    return out;
}

Я хочу знать, почему это происходит, возможные причины:

  • Ошибка компилятора
  • Реализация определяет это поведение
  • Стандарты определяют это поведение
  • Я что-то упустил

Заранее спасибо

Ответы [ 2 ]

6 голосов
/ 08 декабря 2011

Ваш подход не работает и не может работать.Вы не можете вывести «контейнер на основе элемента»!

В качестве простого аргумента рассмотрим этот мысленный эксперимент:

struct Foo { typedef int type; }
struct Bar { typedef int type; }

template <typename T> void deduce_me(typename T::type n) { }

Теперь, если я позвоню deduce_me(5), как мы должнывыведите либо Foo, либо Bar?

1 голос
/ 08 декабря 2011

SequenceCheckResult<int>::directiontype лучше подходит для SequenceCheckResult<int>::directiontype, чем int (потому что это точно), но int лучше, чем SequenceCheckResult<_T>::directiontype (потому что для данной специализации SequenceCheckResult<_T>, directiontype может быть любого типа, даже если мы по крайней мере указали, что это тип с typename).

Редактировать: и, как указывает KerrekSB, даже если directiontype как-то известно как int для всех _T, это лишило бы нас возможности определить, какой _T использовать, что вызывает проблему хотя мы знаем, что на самом деле не имеет значения, какой _T используется.

Чтобы обойти это, определите enum вне класса шаблона. Определение его внутри подразумевает, что оно зависит от _T, когда на самом деле это не так. Это может показаться удобным для обзора, но тот факт, что мы пишем это operator<<, означает, что мы не можем полностью ограничить доступ в любом случае. Кроме того, велика вероятность, что конструкторы и фабричные методы действительно выиграют от внешнего доступа к directiontype.

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