在C ++ 0x中,您可以使用using
关键字继承构造函数,如下所示:
class B { B(int) {} };
class A : public B { using B::B; };
将隐式声明A(int)
构造函数。这适用于模板吗?
class B { B(int) {} };
template<class T> class A : public T { using T::T; };
在T::T
内,我希望编译器找出左手T
,因为在模板参数上使用范围运算符是正常的,但是确定右手T
是构造函数是一个特例。事实上,似乎存在歧义:如果我在T
中有一个名为B
的方法,我试图在A
中添加重载(这就是编译器如何解释这样的使用声明前C ++ 0x)?
答案 0 :(得分:10)
是的,它有效,原因是名称查找机制。继承构造函数声明的工作机制很简单:如果using声明的名称引用基类构造函数,那就是继承构造函数声明。在3.4.3.1 [class.qual] p2,我们发现:
在查找中,构造函数是可接受的查找结果,而嵌套名称说明符指定类C
- 如果在嵌套名称指定者之后指定的名称(在C中查找时)是C的注入类名(第9条),或
- 在作为成员声明的using声明(7.3.3)中,如果在nested-name-specifier之后指定的名称与标识符中的名称相同,或者是最后一个simple-template-id的模板名称嵌套名称说明符的组件
该名称被认为是命名类C的构造函数。
这是使类构造函数定义工作的段落,这也是使继承构造函数声明起作用的段落。在这种情况下,第二个子弹适用:
struct B {
B(int) { }
};
typedef B mytype;
struct A : B {
// "name ... is the same as the identifier ... in the last component ..."
using mytype::mytype;
};
template<typename T> using same = T;
struct C : B {
// "name ... is the same as the template-name ... in the last component ..."
same<B>::same;
};
后一个例证证明在以下情况下也很有用
template<template<typename> class Base>
struct X : Base<int> {
using Base<int>::Base;
};
总结:
上面的第一个子弹是一个语义规则 - 如果嵌套名称说明符后面的名称引用了注入的类名(B::B
或mytype::B
),那么它将被翻译为引用到构造函数。
第二个项目符号是一个语法规则 - 名称必须匹配 - 否则它们的含义无关紧要 - 在提供给Base
的模板参数中可能有一个名为X
的成员,例如在下面,但using声明仍然会导入构造函数并且 not 命名成员Base
:
template<typename T> struct D { private: T Base; };
X<D> x; // valid, the private member is *not* touched!
答案 1 :(得分:7)
是的,从标准(2011年2月草案)第12.9节开始,它似乎确实如此:
template< class T >
struct D : T {
using T::T; // declares all constructors from class T
~D() { std::clog << "Destroying wrapper" << std::endl; }
};
类模板D包装任何类并转发其所有构造函数, 每当一个对象的时候写一条消息到标准日志 D级被摧毁。 - 示例
另外需要注意的是,虽然标准允许,但根据this list,只有1个编译器IBM XLC ++在发行版中支持此功能。 GCC目前仅通过补丁支持它。
编辑:AJG85指出模板中的T总是引用占位符,因此'using T :: T'总是引用模板参数。