С++ шаблон getchas

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

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

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

f.template bar<T>();

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

Ответы

Ответ 1

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

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!
}

Ответ 2

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

#include <vector>
using std::vector;

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

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

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

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

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

"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!

Ответ 3

Звезда вопросов о шаблонах здесь на 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, как указано в OP.

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
}

Ответ 4

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

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 
    … 
}