Страницы

Поиск по вопросам

четверг, 5 декабря 2019 г.

Как компилятор отличает “<” у шаблонов от операции сравнения?

#cpp


Для специализаций шаблонов, например f(1),
и для сравнений, например f < x > (1) используются одни и те же символы,
как компилятор их различает?
    


Ответы

Ответ 1



Все имена должны быть объявлены перед их использованием, поэтому компилятор видит (при помощи поиска имен), что имя это шаблон, и парсит f как специализацию шаблона: template void f(int) {} void g() { f<1>(2); // специализация "f", т.к. "f" была объявлена как шаблон } Первый символ < после имени шаблона f берется как начало списка параметров шаблона. Соответственно, первый не вложенный символ > используется как конец списка параметров шаблона, в том числе и первый символ из последовательности >>: template constexpr int n = 0; // шаблон переменной bool b = n<(2 > 1)>> 0; // ^ ^^ // | || // | |\__знак "меньше" // | \__конец параметров шаблона // \__вложенный знак "меньше" Для шаблонных параметров, чтобы использовать специализацию их шаблона, надо также указывать, что имя является шаблоном: template struct F {}; template void g_bad() { X<0> x; // Ошибка: хотя компилятор знает что "X" это тип, и "меньше" тут не применимо, // но в объявлении "X" не сказано что это шаблон, // по этому его нельзя использовать как шаблон. } template class X> void g_OK() { X<0> x; // ОК, компилятор знает что X - это шаблон } int main() { g_OK(); } В случае имен, зависимых от шаблонных параметров, надо использовать ключевое слово template: struct Foo { template void f(int) {} }; template void g(X x) { x.f<0>(1); // Ошибка: "Foo::f" сравнивается с "0" x.template f<0>(1); // ОК: "template" говорит что "f" это шаблон. } int main() { Foo foo; g(foo); } Ключевое слово template надо использовать после ::, -> или ., чтобы указать что следующее за ним имя - это шаблон. При этом ключевое слово template можно использовать только если тип класса неизвестен в данный момент: класс - это шаблонный параметр, или зависит от шаблонного параметра. Это правило также работает и в ситуациях, когда за именем не следуют шаблонные параметры (<>): template class U = T::template M> // Значение по умолчанию для U зависит от параметра шаблона T. // Т.к. U - это шаблон, то после "T::" надо использовать ключевое слово "template". struct Foo { U<0> u; }; struct Bar { template struct M {}; }; Foo foo; Подробнее об о всем этом можно почитать в главе "14.2 Names of template specializations [temp.names]" стандарта.

Комментариев нет:

Отправить комментарий