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

Jar*_*xle 5 c++ templates visual-studio-2010 c++11 inherited-constructors

这是类foo:

template <typename T>
struct foo
{
    foo()
    {
        t = nullptr;
    }

    foo(T* p, bool flag)
    {
        t = p;
    }
private:
    T* t;
};
Run Code Online (Sandbox Code Playgroud)

这是班级栏:

template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo<T>;
};
Run Code Online (Sandbox Code Playgroud)

它是继承构造函数的正确语法吗?如果我使用"使用foo :: foo;" 那么Visual C++ 2010的编译器就死了.那么基本上如何从VC++ 2010中的模板类继承构造函数呢?

Joh*_*itb 9

template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo<T>;
};
Run Code Online (Sandbox Code Playgroud)

为了让这个解析正确,你需要在template之前插入foo<T>;,告诉编译器foo将被视为模板名称(它不能调查foo<T>告诉自己,因为T是未知的).但是::template在使用声明中不允许使用.该名称也未引用所有构造函数bar:相反,它将引用T此类构造函数的特定构造函数函数模板特化(是模板参数),如下所示

template<typename T>
foo();
Run Code Online (Sandbox Code Playgroud)

另外,对于using声明使用template-id(like foo<T>)作为其名称是无效的(实际上禁止它引用函数模板特化,并且还添加了对名称转换函数模板特化的禁止),所以即使你使用::template(如果可能的话)纠正解析问题,你仍然会在这一点上出错.

当引入继承的构造函数时,添加了允许使用语法规则引用构造函数的特殊规则:如果您具有qualified-id(基本上使用限定名称...::...),并且最后一个部分命名为特定类之前的最后限定,那么你可以用另外两种方式表示该类的构造函数:

  • 如果类是使用模板id(以下形式的名字命名foo<T>),并最后部分模板名称匹配(所以,foo<T>::fooTTP<T>::TTPTTP作为一个模板的模板参数).
  • 如果最后部分匹配的类名(这样,foo::foo或者T::T,与T作为一个模板参数).

这两个附加规则仅在使用声明中有效.它们自然不存在于C++ 03中.C++ 03中也存在的另一个规则是:如果最后一部分命名了注入的类名,那么这个限定名也引用了构造函数:

  • foo::foo为此工作.但仅凭这个规则,T::T(where T表示类foo)将无法工作,因为foo没有成员调用T.

因此,根据特殊规则,您可以编写

using foo<T>::foo;
using bar::foo::foo; // valid too
Run Code Online (Sandbox Code Playgroud)

第二个也是有效的:foo注入的类名是注入基类foo<T>并继承的bar.我们通过引用该名称bar::foo,然后添加最后一部分foo,它再次引用注入的类名,来表示`foo的构造函数.

现在您了解为什么您尝试的初始名称将引用构造函数函数模板特化(如果允许):因为该foo<T>::foo部件将命名所有构造函数,<T>然后接下来将过滤掉模板并传递类型论点.


How*_*ant 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';
}
Run Code Online (Sandbox Code Playgroud)

如果你还没有is_constructible,基本的想法在没有它的情况下工作,但是"继承的构造函数"将过于贪婪.