简单的测试案例:
#includestruct v {}; int main() { std::cout << __VERSION__ << '\n' << (new v < new v) << '\n'; }
我知道比较指针有一个未指定的结果,但这里没有相关性(类似的例子可以通过更多的击键产生,如在后面的coliru片段中).
我方便的C++标准在§14.2第3段中说:
在名称查找后发现名称是模板名称或者operator-function-id或literal-operator-id引用一组重载函数,其中任何成员都是函数模板,如果后面跟着a <,将<始终作为一个的分隔符模板参数列表,从不为小于运算符.
既然v
既不是模板名也不是函数id,我不明白为什么这应该适用.而且,显然,它都没有铿锵作响:
4.2.1 Compatible Clang 3.8.0 (tags/RELEASE_380/final 263969) 1
但是,gcc(6.3.0)抱怨说:
main.cpp: In function 'int main()': main.cpp:4:46: error: 'v' is not a template std::cout << __VERSION__ << '\n' << (new v < new v) << '\n'; ^
我(和铿锵)在这里错过了什么吗?
没有未指定行为的版本:clang gcc
带减运算符的版本而不是小于:gcc(没有编译错误)
Gcc没有相同的功能问题; 使用模板函数时,它坚持<必须是模板参数分隔符,而不是非模板函数.这增加了它是一个bug的论点,因此我将其归档为Bug 79192.
如果有人好奇的话,在我试图回答这个问题的时候出现了这个问题,提问者正在为一个模糊的C++语言写一个语法,并且偶然发现了上述歧义.我想解释一下C++使用的解决方案,但两个编译器之间的差异使得它变得困难.
这是一个错误,或者至少错误报告被GCC维护者接受了.
在评论中,Johannes Schaub-litb指出拒绝此构造的代码位于以下行的第16781行cp/parser.c
:
/* There is no valid C++ program where a non-template type is followed by a "<". That usually indicates that the user thought that the type was a template. */ cp_parser_check_for_invalid_template_id (parser, type, none_type, token->location);
并且评论不正确,因为检查还拒绝其他有效的程序,例如
struct A { operator A(); }; void operator<(A (A::*)(), A); int main() { &A::operator A < A(); }
(在coliru上)