C ++ запутанное имя атрибута для шаблона элемента
Я обнаружил, что при доступе к атрибуту без шаблона (v.foo
) из переменной типа шаблона (T& v
), C ++ можно обмануть, думая, что это шаблон-член, если есть функция шаблона с тем же именем (template class <T> void foo()
). Как это можно объяснить из спецификации C ++? Рассмотрим эту простую программу:
#include <cassert>
/** Determine whether the 'foo' attribute of an object is negative. */
template <class T>
bool foo_negative(T& v)
{
return v.foo < 0;
}
struct X
{
int foo;
};
int main()
{
X x;
x.foo = 5;
assert(!foo_negative(x));
return 0;
}
У нас есть шаблонная функцияfoo_negative
это берет объект любого типа и определяет, является ли его атрибут foo отрицательным.main
функция создаетfoo_negative
с [T = X]. Эта программа компилируется и запускается без вывода.
Теперь добавьте эту функцию в начало программы:
template <class T>
void foo()
{
}
Компиляция с G ++ 4.6.3 приводит к этой ошибке компилятора:
funcs.cpp: In function ‘bool foo_negative(T&)’:
funcs.cpp:13:14: error: parse error in template argument list
funcs.cpp: In function ‘bool foo_negative(T&) [with T = X]’:
funcs.cpp:25:5: instantiated from here
funcs.cpp:13:14: error: ‘foo’ is not a member template function
(Где находится строка 13return v.foo < 0
и строка 25assert(!foo_negative(x))
.)
Clang выдает похожие ошибки.
Wat? Как добавление несвязанной функции, которая никогда не вызывается, привело к появлению синтаксической ошибки в допустимой программе? При разбореfoo_negative
компилятор не знает типv
и, что важно, он не знает,v.foo
это шаблон участника или постоянный участник. По-видимому, он должен решить во время синтаксического анализа (до создания экземпляра шаблона), следует ли рассматривать его как шаблон элемента или как обычный элемент.
Если он думаетv.foo
является членом шаблона, то< 0
рассматривается как проходящий0
в качестве аргумента шаблона, и отсутствует>
отсюда и синтаксическая ошибка. Тогда, когдаfoo_negative
создается с помощью [T = X], есть еще одна ошибка, потому чтоX::foo
не является участником шаблона.
Но почему он думаетv.foo
такое шаблон участника? Эта двусмысленность именно то, чтоtemplate
Ключевое слово для: если я написалv.template foo
тогда я бы явно сказал C ++ ожидать шаблон члена, но я не использовалtemplate
ключевое слово! Я не ссылался на шаблон участника, поэтому следует предположить, что он является постоянным участником. Тот факт, чтоfunction с тем же именем, что и член, не должны иметь никакого эффекта. Почему это? Это не может быть ошибкой в компиляторе, потому что GCC и clang согласованы.