Dan*_*rey 10 c++ gcc templates c++11
我想验证以下是GCC中的错误,而不是我对C++的理解.请考虑以下代码:
struct A
{
struct B
{
template< typename U > U as() const { return U(); }
};
B operator[]( int ) const { return B(); }
};
template< typename T >
struct as
{
template< typename U >
static T call( const U& u )
{
return u[ 0 ].as< T >(); // accepted by Clang 3.2, rejected by GCC 4.7
// return u[ 0 ].template as< T >(); // does not help and is IMHO not needed
// return u[ 0 ].A::B::as< T >(); // accepted by GCC 4.7
}
};
int main()
{
as< int >::call( A() );
}
Run Code Online (Sandbox Code Playgroud)
恕我直言,代码应该没问题,它被Clang 3.2接受,但不是由GCC 4.7接受(4.4和4.6也失败,基本上相同的错误,但4.4产生略有不同的消息).这是我的shell的输出:
$ clang++-3.2 -O3 -Wall -Wextra -std=c++0x t.cc -o t
$ g++-4.7 -O3 -Wall -Wextra -std=c++0x t.cc -o t
t.cc: In static member function ‘static T as<T>::call(const U&)’:
t.cc:17:21: error: invalid use of ‘struct as<T>’
t.cc: In static member function ‘static T as<T>::call(const U&) [with U = A; T = int]’:
t.cc:18:4: warning: control reaches end of non-void function [-Wreturn-type]
$
Run Code Online (Sandbox Code Playgroud)
问题:这是GCC中的错误还是我错过了什么?
编辑:我有点困惑:在http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55576上的GCC错误报告在评论#9中说评论#3中的代码是"有效的".这到底是什么意思?看起来像海湾合作委员会的人认为它实际上是一个错误,否则他们已经关闭它了?OTOH来自@Potatoswatter的答案似乎很清楚它应该是正确的我应该提交针对Clang的错误报告(或者是否已经有这样的错误报告?)
请注意,在澄清上述内容之前,我犹豫是否将答案标记为已接受.由于两个答案都已经有用(一个解释,一个解决),我给了两个赞成.
奖金问题:由于我得到了一个非叙事代码的downvote,我想知道其他人的感受.我试图创建一个SCCEE,它可以消除所有干扰,并专注于技术问题.这就是我更喜欢考虑这些事情的方式.那是错的吗?
另外,@ EdHal:为什么代码容易发生灾难?(你不认为这是我拥有的真实世界代码,对吧?)
编辑2 :谢谢,大卫,刚注意到你的编辑.我现在已经接受了你的回答,我也看到你对GCC错误报告发表了评论.我认为这个问题的要点得到了回答,海湾合作委员会再次提醒.感谢大家.
这是该语言的一个棘手的角落.GCC正在应用C++03§3.4.5/ 1中的规则:
在类成员访问表达式(5.2.5)中,如果
.或->标记后面紧跟着标识符后跟a<,则必须查找标识符以确定它是否<是模板参数列表的开头(14.2)或更少 - 运营商.首先在对象表达式的类中查找标识符.如果未找到标识符,则在整个postfix-expression的上下文中查找它,并命名一个类或函数模板.如果对象表达式的类中的查找找到模板,则还会在整个后缀表达式的上下文中查找该名称,- 如果未找到名称,则使用在对象表达式的类中找到的名称,否则使用
- 如果在整个postfix-expression的上下文中找到该名称并且未命名类模板,则使用在对象表达式的类中找到的名称,否则
- 如果找到的名称是类模板,则它必须引用与在对象表达式的类中找到的实体相同的实体,否则程序将是格式错误的.
请注意,此过程无用,因为template已经需要关键字来消除<令牌的歧义,因为子表达式的类型u[0]取决于模板参数.
这样做的原因是在嵌套名称限定符中使用template-id的情况下简化解析,例如u[ 0 ].as< T >::bar.baz,哪里bar是基类的typedef.
C++ 11删除了三个要点,简化了流程
首先在对象表达式的类中查找标识符.如果未找到标识符,则在整个postfix-expression的上下文中查找它,并命名一个类模板.
所以这是一个错误,而不是我之前说过的旧错误.需要删除名称查找角区.
此外,看起来这个怪癖可能被利用来允许单个模板化表达式交替引用类或函数.不确定这是否有用,但它是C++ 11中的新功能.