C ++ 11标准的N3337草案在[namespace.udecl]
using声明在声明区域中引入了一个名称,其中出现了using声明。
每个using声明都是声明和成员声明,因此可以在类定义中使用。
在用作成员声明的using声明中,nested-name-specifier应命名一个基类。 正在定义的类。
这通常用于在派生类的基类public中创建受保护的typedef,如下例所示,它在最新版本的Clang中成功编译:
struct A
{
protected:
typedef int Type;
};
struct B : A
{
using A::Type;
};
B::Type x;
using声明可以引用模板类。这编译:
struct A
{
protected:
template<typename T>
struct Type
{
};
};
struct B : A
{
using A::Type;
};
B::Type<int> x;
也可以引用依赖基类中的模板。以下编译成功(使用typedef注释。)
template<typename T>
struct A
{
protected:
template<typename U>
struct Type
{
};
};
template<typename T>
struct B : A<T>
{
using /* typename */ A<T>::Type; // A<T> is dependent, typename required?
// typedef Type<int> IntType; // error: unknown type name 'Type'
};
B<int>::Type<int> x;
取消注释typename
会在实例化B<int>
时导致错误:&#34;错误:&#39; typename&#39;在非类型&#34;。
取消注释typedef会在第一次实例化之前解析B
时导致错误。我猜这是因为编译器不会将Type
视为依赖类型名称。
[namespace.udecl]
的最后一段建议使用声明可以指定依赖名称,并且必须使用typename
关键字才能消除对引入名称的进一步使用的歧义:
如果using声明使用关键字typename并指定依赖名称(14.6.2),则引入名称 by-declaration被视为typedef-name
我对[temp.dep]
的解读表明A<T>::Type
是一个从属名称。从逻辑上讲,using-declaration引入的名称也应该是依赖的,但[temp.dep]
没有明确提到依赖using声明的情况。我错过了什么吗?
答案 0 :(得分:2)
问题是Type
不是类,而是类模板。您可以执行以下操作(这样您告诉编译器Type
是B
范围内的类模板:
template<typename T>
struct B : A<T>
{
using A<T>::Type;
typedef typename B::template Type<int> IntType;
};
实际上,在你的第二个例子中为了typedef
写IntType
,你必须这样做。
答案 1 :(得分:0)
是的,具有依赖qualified-id的类成员using声明引入了依赖名称。
[namespace.udecl]
using声明在声明区域中引入了一个名称,其中出现了using声明。
如果引入的名称是依赖的,它仍然是依赖的 - 我找不到任何其他建议。
但是,using-declaration语法不提供指定依赖名称是模板的方法。对Type
中的从属名称B
的后续引用可能会或可能不会引用模板,因此无法解析Type<int>
。
以下示例演示了依赖的using声明的有效用法。
template<typename T>
struct A
{
protected:
struct Type
{
typedef int M;
};
};
template<typename T>
struct B : A<T>
{
using typename A<T>::Type;
typedef typename Type::M Type2;
};
B<int>::Type2 x;