'using' 语句用 g++ 编译,用 clang 编译失败

A 'using' statement compiles with g++, fails compilation with clang

我有以下结构的代码(在现实中当然要复杂得多,尤其是 "Base" 是一个三行代码,但我试图抓住它的要点):

template <class T>
class A {};

template <class T>
class B {
public:
    B(){};
};

template <class T>
class C : public B<A<T>> {
public:
    using Base = B<A<T>>;
    using Base::B;
};

static const C<int> c{};

通过

,代码可以通过 g++ 正常编译
g++ -c test.cpp -std=c++11

但是,使用 clang++ 我收到一条我不太理解的错误消息

clang++ -c test.cpp -std=c++11

test.cpp:14:14: error: dependent using declaration resolved to type without 'typename' using Base::B;

我的代码有什么问题吗?或者这是 clang 中的错误?

注意:在编写 using B<A<T>>::B; 时,它可以在两个编译器上正常编译,但这并不是我的问题的真正解决方案。

编辑:clang版本为3.5.0,gcc版本为4.9.2

来自第 12.1 节:

Constructors do not have names

所以通常的限定查找规则不适用。相反,您必须依赖构造函数查找的特殊规则(第 3.4.3.1 节):

In a lookup in which function names are not ignored and the nested-name-specifier nominates a class C:

— if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C, or

in a using-declaration (7.3.3) that is a member-declaration, if the name specified after the nested-name-specifier is the same as the identifier or the simple-template-id’s template-name in the last component of the nested-name-specifier,

the name is instead considered to name the constructor of class C.

所以你当然可以写

using Base::Base;

而不是

using Base::B;

您的原始版本应该在第一个要点下工作,但注入-class-名称在涉及模板时会变得复杂。只需使用更简单的版本 Base::Base,它也更具可读性。任何看到它的人都会立即知道您正在命名构造函数。

这个案例已经在 C++ 委员会中讨论过(根据 Richard Smith https://llvm.org/bugs/show_bug.cgi?id=23107#c1),现在事情变得更清楚了:

using Base::B

不是有效代码。

下面的方法是引入class别名Base时构造函数继承的正确表达方式:

using Base::Base

但是,clang 产生的错误消息具有误导性,希望能作为此错误报告的一部分得到解决 (https://llvm.org/bugs/show_bug.cgi?id=22242)。