Does inheriting constructors work with templates in C++0x?

前端 未结 2 628
灰色年华
灰色年华 2020-12-29 04:33

In C++0x, you can use the using keyword to inherit constructors, like so:

class B { B(int) {} };

class A : public B { using B::B; };

相关标签:
2条回答
  • 2020-12-29 05:09

    Yes, it appears it does, from the standard (Feb 2011 Draft), section 12.9:

    template< class T >
    struct D : T {
    using T::T; // declares all constructors from class T
    ~D() { std::clog << "Destroying wrapper" << std::endl; }
    };
    

    Class template D wraps any class and forwards all of its constructors, while writing a message to the standard log whenever an object of class D is destroyed. —end example

    Another thing to note, while the standard allows it, according to this list, only 1 compiler, IBM XLC++, supports this feature in a release version. GCC only currently supports it with a patch.

    Edit: AJG85 pointed out that the T in the template always refers to the placeholder, so the 'using T::T' always refers to the template argument.

    0 讨论(0)
  • 2020-12-29 05:10

    Yes it works, and the reason is the name lookup mechanism. The mechanism a inheriting-constructors declaration works is simple: If the using declaration's name refers to base class constructors, that's an inheriting constructors declaration. At 3.4.3.1[class.qual]p2 we find:

    In a lookup in which the constructor is an acceptable lookup result and the nested-name-specifier nominates a class C

    • if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C (Clause 9), or
    • in a using-declaration (7.3.3) that is a member-declaration, if the name specified after the nested-name-specifier is the same as the identifier or the simple-template-id's template-name in the last component of the nested-name-specifier

    the name is instead considered to name the constructor of class C.

    This is the paragraph that makes out of class constructor definitions work, and this is also the paragraph that makes inheriting constructor declarations work. The second bullet applies in this case:

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

    The latter example proves also useful in cases such as the following

    template<template<typename> class Base>
    struct X : Base<int> {
      using Base<int>::Base;
    };
    

    In summary:

    • The first bullet above is a semantic rule - if the name after the nested name specifier refers to the injected class name (B::B or mytype::B), then it will be translated to refer to the constructor(s).

    • The second bullet is a syntactic rule - the names just must match - their meaning is irrelevant otherwise - there could have been a member called Base in the template argument provided to X, such as in the following, but the using declaration would still import the constructors and do not name the member Base:

      template<typename T> struct D { private: T Base; };
      X<D> x; // valid, the private member is *not* touched!
      
    0 讨论(0)
提交回复
热议问题