验证GCC中的错误

Verify bug in GCC

本文关键字:错误 GCC 验证      更新时间:2023-10-16

我想验证以下是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() );
}

IMHO代码应该是好的,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]
$ 

问题:这是GCC中的错误还是我遗漏了什么?

编辑:我有点困惑:GCC错误报告http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55576在注释#9中表示注释#3中的代码是"有效的"。这到底意味着什么?看起来GCC的人认为它实际上是一个bug,否则他们会已经关闭它了吗?OTOH来自@Potatoswatter的答案似乎很清楚,它应该是正确的,我应该针对Clang提交一份错误报告(或者已经有这样的错误报告了吗?(

请注意,在澄清上述内容之前,我不愿意将答案标记为已接受。由于两个答案都很有帮助(一个可以解释,一个可以解决(,我给了两个都赞成票。

额外的问题:由于我对非叙事性代码投了反对票,我想知道其他人的感受。我试图创建一个SCCEE,它可以消除所有干扰,专注于技术问题。这就是我喜欢思考这些事情的方式。这错了吗?

此外,@EdHeal:为什么代码容易发生灾难?(你不认为这是我的真实世界代码,对吧?(

编辑2:谢谢,大卫,刚刚注意到你的编辑。我现在将您的回答标记为已接受,我还看到您对GCC错误报告发表了评论。我认为这个问题的要点由此得到了回答,海湾合作委员会得到了另一个提醒。谢谢大家。

这是语言中一个棘手的角落。GCC正在应用C++03§3.4.5/1:中的规则

在类成员访问表达式(5.2.5(中,如果.->标记后面紧接着一个标识符,然后是<,则必须查找该标识符,以确定<是模板参数列表(14.2(的开头还是小于运算符。标识符首先在对象表达式的类中查找。如果找不到标识符,则在整个后缀表达式的上下文中查找该标识符,并命名一个类或函数模板。如果在对象表达式的类中查找找到一个模板,则还会在整个后缀表达式和的上下文中查找该名称

--如果找不到名称,则使用在对象表达式的类中找到的名称,否则为

--如果名称是在整个后缀表达式的上下文中找到的,并且没有命名类模板,则使用在对象表达式的类中找到的名称,否则为

--如果找到的名称是类模板,则它必须引用与对象表达式的类中找到的实体相同的实体,否则程序格式不正确

请注意,这个过程是无用的,因为template关键字已经被要求消除<标记的歧义,因为子表达式u[0]的类型取决于模板参数。

这样做的原因是在嵌套名称限定符中使用模板id的情况下简化解析,例如u[ 0 ].as< T >::bar.baz,其中bar是基类的typedef。

C++11删除了三个要点,简化了的过程

标识符首先在对象表达式的类中查找。如果找不到标识符,则在整个后缀表达式的上下文中查找该标识符,并命名一个类模板。

所以这是一个bug,而不是我之前说过的旧bug。需要删除名称查找角大小写。

此外,这个怪癖似乎可以被利用来允许单个模板化表达式交替引用类或函数。不确定这是否有用,但它在C++11中是新的。

问题是as作为类和模板名称被注入到template<...> struct as的作用域中;这就是gcc抱怨"invalid use of ‘struct as<T>’"的原因。

我不太确定gcc是否正确(这取决于成员表达式上的名称查找规则(,但解决方法是使用decltype:

    return u[ 0 ].decltype(u[ 0 ])::template as< T >();