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 согласованы.

Ответы на вопрос(3)

Ваш ответ на вопрос