Неоднозначность шаблона C ++
Вопрос
Мы с другом обсуждали шаблоны C ++.Он спросил меня, что это должно сделать:
#include <iostream>
template <bool>
struct A {
A(bool) { std::cout << "bool\n"; }
A(void*) { std::cout << "void*\n"; }
};
int main() {
A<true> *d = 0;
const int b = 2;
const int c = 1;
new A< b > (c) > (d);
}
Последняя строка в main содержит два разумных разбора.Является ли 'b' аргументом шаблона или b > (c)
аргумент шаблона?
Хотя скомпилировать это и посмотреть, что мы получим, тривиально, нам было интересно, что устраняет двусмысленность?
Решение
AFAIK, это было бы скомпилировано как new A<b>(c) > d
.Это единственный разумный способ разобрать его, ИМХО.Если синтаксический анализатор не может предположить при обычных обстоятельствах a > end аргумент шаблона, это привело бы к гораздо большей двусмысленности.Если вы хотите, чтобы было по-другому, вам следовало бы написать:
new A<(b > c)>(d);
Другие советы
Как указано Leon & Lee, 14.2 / 3 (C ++ '03) явно определяет это поведение.
C ++ '0x добавляет веселья, применяя аналогичное правило к >>
.Основная концепция заключается в том, что при разборе списка шаблонов-аргументов не вложенный >>
будут рассматриваться как два различных >
>
токены, а не оператор правильного сдвига:
template <bool>
struct A {
A(bool);
A(void*);
};
template <typename T>
class C
{
public:
C (int);
};
int main() {
A<true> *d = 0;
const int b = 2;
const int c = 1;
new C <A< b >> (c) > (d); // #1
new C <A< b > > (c) > (d); // #2
}
'#1' и '#2' эквивалентны в приведенном выше примере.
Это, конечно, устраняет проблему с добавлением пробелов во вложенных специализациях:
C<A<false>> c; // Parse error in C++ '98, '03 due to "right shift operator"
Стандарт C ++ определяет, что если для имени шаблона, за которым следует <
, тот самый <
всегда является началом списка аргументов шаблона и первым не вложенным >
берется в конце списка аргументов шаблона.
Если вы предполагали, что результат >
operator является аргументом шаблона, тогда вам нужно будет заключить выражение в круглые скобки.Вам не нужны круглые скобки, если аргумент был частью static_cast<>
или другое шаблонное выражение.
Жадность лексера, вероятно, является определяющим фактором в отсутствии круглых скобок, делающих его явным.Я бы предположил, что лексер не жадный.