Шаблон C++ получил

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

template<class C> class F00 {
   template<typename T> bar();
};
...
Foo<C> f;
f.bar<T>(); // syntax error here

Теперь я понимаю, что шаблонные скобки обрабатываются как операторы отношений. Чтобы сделать то, что предполагалось, необходим следующий причудливый синтаксис, см. Шаблоны: функция шаблона не очень хорошо работает с функцией-членом класса класса:

f.template bar<T>();

Какие еще странные аспекты и особенности шаблонов C++/C++, с которыми вы столкнулись, не были чем-то, что вы считаете общеизвестным?

4 ответа

Я получил путаницу в первый раз, когда унаследовал шаблонный класс от другого шаблонного класса:

template<typename T>
class Base {
    int a;
};

template<typename T>
class Derived : public Base<T> {
    void func() {
        a++; // error! 'a' has not been declared
    }
};

Проблема в том, что компилятор не знает, Base<T> будет шаблоном по умолчанию или специализированным. Специализированная версия может не иметь int a как член, поэтому компилятор не предполагает, что он доступен. Но вы можете сказать компилятору, что он будет там с using директива:

template<typename T>
class Derived : public Base<T> {
    using Base<T>::a;
    void func() {
        a++; // OK!
    }
};

Кроме того, вы можете сделать явным, что вы используете член T:

void func {
    T::a++; // OK!
}

Это меня расстроило тогда:

#include <vector>
using std::vector;

struct foo {
  template<typename U>
  void vector();
};

int main() {
  foo f;
  f.vector<int>(); // ambiguous!
}

Последняя строка в main неоднозначна, потому что компилятор не только ищет vector в foo, но также как неквалифицированное имя, начинающееся изнутри main, Так что находит оба std::vector а также foo::vector, Чтобы это исправить, нужно написать

f.foo::vector<int>();

GCC не заботится об этом и принимает приведенный выше код, выполняя интуитивно понятную вещь (вызывая член), другие компиляторы работают лучше и предупреждают, как comeau:

"ComeauTest.c", line 13: warning: ambiguous class member reference -- function
          template "foo::vector" (declared at line 8) used in preference to
          class template "std::vector" (declared at line 163 of
          "stl_vector.h")
        f.vector<int>(); // ambiguous!

Звезда вопросов о шаблонах здесь на SO: отсутствующее имя!

template <typename T>
class vector
{
  public:
    typedef T * iterator;
    ...
};

template <typename T>
void func()
{
    vector<T>::iterator it;           // this is not correct!

    typename vector<T>::iterator it2; // this is correct.
}

Проблема здесь в том, что vector<T>::iterator является зависимым именем: оно зависит от параметра шаблона. Как следствие, компилятор не знает, что iterator обозначает тип; мы должны сказать ему с typename ключевое слово.

То же самое касается шаблонных внутренних классов или шаблонных / статических функций: они должны быть устранены с помощью template Ключевое слово, как отмечено в ОП.

template <typename T>
void func()
{
    T::staticTemplateFunc<int>();          // ambiguous

    T::template staticTemplateFunc<int>(); // ok

    T t;

    t.memberTemplateFunc<int>();          // ambiguous

    t.template memberTemplateFunc<int>(); // ok
}

Определение функции-члена вне области видимости:

template <typename T> 
class List {                     // a namespace scope class template 
  public: 
    template <typename T2>       // a member function template 
    List (List<T2> const&);      // (constructor) 
    … 
}; 
template <typename T> 
 template <typename T2> 
List<T>::List (List<T2> const& b) // an out-of-class member function 
{                                 // template definition 
    … 
} 
Другие вопросы по тегам