c ++ 0x继承模板中的构造函数

时间:2011-03-23 20:28:46

标签: c++ visual-studio-2010 templates c++11 inherited-constructors

这是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中的模板类继承构造函数呢?

4 个答案:

答案 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(基本上是使用...::...的限定名称),并且之前是最后一个限定的最后一部分命名一个特定的类,然后你可以用另外两种方式表示该类的构造函数:

  • 如果使用template-id(表单foo<T>的名称)命名该类,并且最终部分与模板名称匹配(那么,foo<T>::fooTTP<T>::TTP与{{ 1}}是模板模板参数。)。
  • 如果最终部分与班级名称匹配(因此,TTPfoo::fooT::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支持是实验性的,并且可以随着找到错误等而发生变化。