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

发布于 2024-10-26 02:11:38 字数 452 浏览 2 评论 0原文

这是 foo 类:

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

    foo(T* p, bool flag)
    {
        t = p;
    }
private:
    T* t;
};

这是 bar 类:

template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo<T>;
};

继承构造函数的语法是否正确?如果我使用“using foo::foo;”然后Visual C++ 2010的编译器就死掉了。 那么基本上如何在 VC++ 2010 中从模板类继承构造函数呢?

Here is class foo:

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

    foo(T* p, bool flag)
    {
        t = p;
    }
private:
    T* t;
};

Here is class bar:

template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo<T>;
};

Is it correct syntax for inheriting constructors? If I use "using foo::foo;" then compiler of Visual C++ 2010 dies.
So basically how to inherit constructors from template classes in VC++ 2010?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

所谓喜欢 2024-11-02 02:11:38
template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo<T>;
};

为了让这个解析正确,您需要在 foo; 之前插入 template,以告诉编译器 foo 是被视为模板名称(它无法通过 foo 来告诉自己,因为 T 未知)。但是在 using 声明中不允许使用 ::template 。该名称也并不引用 bar 的所有构造函数:相反,它会引用此类构造函数的特定构造函数模板特化(T 是模板参数):此外

template<typename T>
foo();

,使用 template-id (如 foo)作为其名称的 using 声明是无效的(这实际上禁止它引用函数模板专门化,还禁止名称转换函数模板专门化),因此即使您使用 ::template 纠正解析问题(如果可能的话),您仍然会出错此时出来。

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

  • 如果该类是使用 template-id 命名的(形式为 foo),最后部分与模板名称匹配(因此,foo::fooTTP::TTP其中 TTP 是模板模板参数)。
  • 如果最后部分与类名匹配(因此,foo::fooT::T,其中 T 是模板参数)。

这两个附加规则仅在 using 声明中有效。而它们自然不会出现在 C++03 中。 C++03 中也存在的另一个规则是:如果最后部分命名了注入的类名,则该限定名称也引用构造函数:

  • foo::foo 将因此起作用。但仅使用此规则,T::T(其中 T 表示类 foo)将不起作用,因为 foo > 没有名为 T 的成员。

因此,有了特殊规则,您可以编写

using foo<T>::foo;
using bar::foo::foo; // valid too

第二个也是有效的: foo 是注入的类名,它被注入到基类 foo 中并继承到。我们通过 bar::foo 引用该名称,然后添加最后一部分 foo,它再次引用注入的类名,以表示`富。

现在您明白为什么您尝试的初始名称将引用构造函数模板特化(如果允许的话):因为 foo::foo 部分将命名所有构造函数,并且随后的 将过滤掉模板并传递类型参数。

template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo<T>;
};

To let this parse correctly, you would need to insert template before the foo<T>;, to tell the compiler that foo is to be regarded as a template name (it cannot look into foo<T> to tell itself, since T is unknown). But using ::template is not allowed in a using declaration. The name also does not refer to all constructors of bar: Instead, it would refer to a specific constructor function template specialization (T is the template argument) of such a constructor as follows

template<typename T>
foo();

In addition, it's not valid for a using declaration to use a template-id (like foo<T>) as its name (which in effect forbids it to refer to function template specialization, with the addition of forbidding to name conversion function template specializations stated too), so even if you correct the parsing problem using ::template (if it would be possible), you would still error out at this point.

When inherited constructors were introduced, special rules were added that allow to reference a constructor using a syntactic rule: If you have a qualified-id (which basically a qualified name using ...::...), and the last qualified before the final part names a specific class, then you can denote the constructor(s) of that class in two additional ways:

  • If the class was named using a template-id (a name of the form foo<T>) and the final part matches the template name (so, foo<T>::foo or TTP<T>::TTP with TTP being a template template parameter).
  • If the final part matches the class name (so, foo::foo or T::T, with T being a template parameter).

These two additional rules are only active in a using declaration. And they were naturally not present in C++03. The other rule that was also present in C++03 is: If the final part names the injected class name, then this qualified name also refers to the constructor:

  • foo::foo would therefor work. But with this rule alone, T::T (where T denotes class foo) would not work, because foo has no member called T.

Therefor, with the special rules in place you can write

using foo<T>::foo;
using bar::foo::foo; // valid too

The second is valid too: foo is the injected class name which was injected into the base class foo<T> and inherited to bar. We refer to that name by bar::foo, and then add the last part foo, which refers to the injected class name again, to denote the constructor(s) of `foo.

Now you understand why the initial name you tried would refer to a constructor function template specialization (if it were to be allowed to): Because the foo<T>::foo part would name all constructors, and the <T> that would follow would then filter out the template and pass the type argument.

孤独患者 2024-11-02 02:11:38

如果您的编译器尚不支持继承构造函数,但支持可变参数宏、可变参数模板和右值引用,以及非常方便的 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,则基本思想无需它即可工作,但是“继承的构造函数”会过于贪婪。

If your compiler doesn't yet support inheriting constructors, but does support variadic macros, variadic templates and rvalue references, and a really handy type_trait, here's a really decent workaround:

#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';
}

If you don't have is_constructible yet, the basic idea works without it, but the "inherited constructor" will be overly greedy.

你列表最软的妹 2024-11-02 02:11:38

你不需要第二个模板参数;

template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo;
};

应该

编辑 我撤回这适用于 g++-4.4.1,但是当该功能可用时,这应该是正确的语法

you don't need the second template parameter;

template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo;
};

should do

edit i withdraw that this works on g++-4.4.1, however this should be the correct syntax when the feature becomes available

明天过后 2024-11-02 02:11:38

其他答案已经很好地解释了 C++0x 中继承构造函数的工作原理。然而,截至撰写本文时,还没有编译器完全实现整个 C++0x 功能集。不幸的是,这意味着 VC++ 2010 尚不支持继承构造函数。

C++0x 标准尚未发布。标准的最终草案将于3 月,但 ISO 还需要几个月的时间才能发布。在此期间,编译器编写者正在推出一些功能,以便在标准最终确定时它们尽可能兼容 C++0x。

我相信最新版本的 GCC 支持继承构造函数,所以如果你现在必须尝试一下,你可以使用它。当然,C++0x 支持是实验性的,可能会随着错误的发现等而发生变化。

The other answers have already done a good job of explaining how inheriting constructors in C++0x work. However, as of this writing, no compiler has completely implemented the entire C++0x feature set. Unfortunately that means VC++ 2010 does not yet support inheriting constructors.

The C++0x standard has not yet been published. The final draft of the standard will be finished sometime in March, but it'll take a few more months for ISO to publish it. During that time, compiler writers are rolling out features so they'll be as C++0x compliant as possible when the standard is finalized.

I believe the latest version of GCC supports inheriting constructors, so if you must try it out now, you can use that. Of course, C++0x support is experimental and subject to change as bugs are found, etc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文