Using declaration for type-dependent template name

2019-04-04 04:19发布

When CRTP is used inside a template, (or generally when a template parameter is passed as a base class template argument), is it impossible to name the base's member templates in a using declaration?

template< typename d >
struct base {
    template< typename >
    struct ct {};

    template< typename >
    void ft() {}
};

template< typename x >
struct derived : base< derived< x > > {
     using derived::base::template ct; // doesn't work
     using derived::base::ft; // works but can't be used in a template-id
};

It seems to me that this is a hole in the language, simply because the using-declaration grammar production doesn't incorporate a qualified-id.

using-declaration:
    using typename(opt) nested-name-specifier unqualified-id ; // have this
    using :: unqualified-id ;

unqualified-id:
    identifier
    operator-function-id
    conversion-function-id
    literal-operator-id
    ~ class-name
    ~ decltype-specifier
    template-id

qualified-id:
    nested-name-specifier template(opt) unqualified-id // want this
    :: identifier
    :: operator-function-id
    :: literal-operator-id
    :: template-id

If the only rule were using-declaration: using typename(opt) qualified-id, the only consequences would be

  • ruling out :: conversion-function-id, :: ~ class-name, and :: ~ decltype-specifier template-id which make no semantic sense,
  • allowing :: template-id which is already expressly forbidden by 7.3.3/5, and
  • allowing the template keyword which already has sufficient specification to patch the hole.

Is this analysis correct?

Given that the new grammar were allowed, perhaps a declaration with typename should import a class template or alias template, and one without typename should import a function or variable template into the current scope.

     using typename derived::base::template ct;
     using derived::base::ft;

This might require some additional specification. Also, the current status quo seems to be that dependent template-names always have ambiguous kind (not template-ids), so it's not clear that typename belongs with ct at all.

1条回答
甜甜的少女心
2楼-- · 2019-04-04 04:57

The following works fine with C++11:

#include <iostream>

template< typename d >
struct base {
    template< typename >
    struct ct {};

    template< typename >
    void ft() {std::cerr << "cheesecake" << std::endl;}
};

template< typename x >
struct derived : base< derived< x > > {
  template<typename X>
    using ct = typename derived::base::template ct<X>; // new in C++11
  using derived::base::ft;
};

int main()
{
  derived<int>::ct<float> c;
  derived<int> a;
  a.ft<int>();
}

If that is not what you wanted, can you please give an example of how you would want to use ct and ft?

查看更多
登录 后发表回答