С++ шаблон 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
…
}