这是foo类:
template <typename T>
struct foo
{
foo()
{
t = nullptr;
}
foo(T* p, bool flag)
{
t = p;
}
private:
T* t;
};
这是课程栏:
template <typename T>
struct bar: public foo<T>
{
using foo<T>::foo<T>;
};
继承构造函数的语法是否正确?如果我使用“使用foo :: foo;”那么Visual C ++ 2010的编译器就死了。 那么基本上如何从VC ++ 2010中的模板类继承构造函数呢?
答案 0 :(得分:9)
template <typename T>
struct bar: public foo<T>
{
using foo<T>::foo<T>;
};
要正确解析,您需要在template
之前插入foo<T>;
,告诉编译器foo
被视为模板名称(它无法查看) foo<T>
告诉自己,因为T
未知)。但是在使用声明中不允许使用::template
。该名称也未引用bar
的所有构造函数:相反,它将引用此类构造函数的特定构造函数模板特化(T
是模板参数),如下所示
template<typename T>
foo();
此外,使用template-id
(如foo<T>
)作为名称使用声明无效(实际上禁止它引用函数模板特化,添加了禁止使用也可以命名为转换函数模板特化项,所以即使你使用::template
来纠正解析问题(如果可能的话),你仍然会在这一点上出错。
当引入继承的构造函数时,添加了允许使用语法规则引用构造函数的特殊规则:如果您有一个qualified-id(基本上是使用...::...
的限定名称),并且之前是最后一个限定的最后一部分命名一个特定的类,然后你可以用另外两种方式表示该类的构造函数:
foo<T>
的名称)命名该类,并且最终部分与模板名称匹配(那么,foo<T>::foo
或TTP<T>::TTP
与{{ 1}}是模板模板参数。)。TTP
或foo::foo
,T::T
是模板参数)。 这两个附加规则仅在使用声明中有效。它们自然不存在于C ++ 03中。 C ++ 03中也存在的另一个规则是:如果最后一部分命名了注入的类名,那么这个限定名也引用了构造函数:
T
会因此而工作。但仅使用此规则,foo::foo
(其中T::T
表示类T
)将无效,因为foo
没有名为foo
的成员。 因此,根据特殊规则,您可以编写
T
第二个也是有效的:using foo<T>::foo;
using bar::foo::foo; // valid too
是注入的类名,它被注入基类foo
并继承到foo<T>
。我们通过bar
引用该名称,然后添加最后一部分bar::foo
,它再次引用注入的类名,以表示`foo的构造函数。
现在您了解为什么您尝试的初始名称将引用构造函数函数模板特化(如果允许):因为foo
部分将命名所有构造函数,foo<T>::foo
然后将过滤出模板并传递类型参数。
答案 1 :(得分:6)
如果您的编译器还不支持继承构造函数,但支持可变参数宏,可变参数模板和右值引用,以及非常方便的type_trait,这里有一个非常好的解决方法:
#include <type_traits>
#include <utility>
#include <ostream>
enum Color {Red, Blue};
#define USING(Derived, Base) \
template<typename ...Args, \
typename = typename std::enable_if \
< \
std::is_constructible<Base, Args...>::value \
>::type> \
Derived(Args &&...args) \
: Base(std::forward<Args>(args)...) { } \
template<typename Mixin>
class add_color
: public Mixin
{
Color color;
public:
USING(add_color, Mixin);
friend std::ostream& operator<<(std::ostream& os, const add_color& x)
{
switch (x.color)
{
case Red:
os << "Red";
break;
case Blue:
os << "Blue";
break;
}
os << ' ' << x.first << ' ' << x.second;
return os;
}
};
#include <string>
#include <iostream>
int main()
{
add_color<std::pair<std::string, int>> x1("five", 5);
std::cout << "x1 = " << x1 << '\n';
add_color<std::pair<std::string, int>> x3;
std::cout << "x3 = " << x3 << '\n';
add_color<std::pair<std::string, int>> x4 = x1;
std::cout << "x4 = " << x4 << '\n';
std::pair<std::string, int> p;
add_color<std::pair<std::string, int>> x5 = p;
std::cout << "x5 = " << x5 << '\n';
}
如果你还没有is_constructible,基本的想法在没有它的情况下有效,但是“继承的构造函数”会过于贪婪。
答案 2 :(得分:3)
您不需要第二个模板参数;
template <typename T>
struct bar: public foo<T>
{
using foo<T>::foo;
};
应该
编辑我撤回说这适用于g ++ - 4.4.1,但是当功能可用时,这应该是正确的语法
答案 3 :(得分:2)
其他答案已经很好地解释了C ++ 0x中继承构造函数的工作方式。但是,在撰写本文时,没有编译器完全实现了整个C ++ 0x功能集。不幸的是,这意味着VC ++ 2010还不支持继承构造函数。
C ++ 0x标准尚未发布。标准will be finished sometime in March的最终草案,但ISO需要几个月才能发布它。在此期间,编译器编写者正在推出功能,以便在标准最终确定时尽可能符合C ++ 0x。
我相信最新版本的GCC支持继承构造函数,所以如果你现在必须尝试,你可以使用它。当然,C ++ 0x支持是实验性的,并且可以随着找到错误等而发生变化。