C++ использование объявления с typename в наследовании-конструкторы

во время чтения этот вопрос, я нашел странный момент:

template <typename T>
class Subclass : public Baseclass<T>
{
public:
    using typename Baseclass<T>::Baseclass;
    //    ^^^^^^^^
};

С typename, Baseclass<T>::Baseclass должно быть вводят имя класса, не конструктор. Насколько я знаю, это тот же случай, что и этот:

template <typename T>
class Base
{
public:
    typedef short some_type;
};

template <typename T>
class Sub : public Base<T>
{
public:
    using typename Base<T>::some_type;
};

чтобы убедиться, я написал тестовый код.

#include <iostream>

template <typename T>
class Base
{
public:
    Base() { std::cout << "A::A()n"; }
    Base(int) { std::cout << "A::A(int)n"; }
    Base(const char *) { std::cout << "A::A(const char *)n"; }
};

template <typename T>
class Sub : public Base<T>
{
    using typename Base<T>::Base;
};

int main()
{
    Sub<char> s1;
    Sub<char> s2(3);
    Sub<char> s3("asdf");
}

однако он работает на gcc 4.8.3.

$ g++ -std=c++1y -Wall -Wextra -Werror -pedantic test.cpp -o test && ./test
A::A()
A::A(int)
A::A(const char *)

он также работает без typename.

$ cat test.cpp
...
    using Base<T>::Base;
...

$ g++ -std=c++1y -Wall -Wextra -Werror -pedantic test.cpp -o test && ./test
A::A()
A::A(int)
A::A(const char *)

почему я получил эти результаты? Что я пропустил?

2 ответов


стандарт довольно ясно об этом ([пространство имен.udecl]/1)

С помощью декларации:

использование typename_opt nested-name-specifier unqualified-id;

на ключевое слово-это дополнительно часть объявления using, которое может отображаться даже для использования объявлений не-типов. Поэтому следующий код должен быть стандартным:

template < typename T > class Base {
  protected:
    typedef T Ttype;
    Ttype member;

  public:
    Base() {
        std::cout << "A::A()\n";
    }
    Base(int) {
        std::cout << "A::A(int)\n";
    }
    Base(const char *) {
        std::cout << "A::A(const char *)\n";
    }

  protected:
    void memfunc(void) {
        std::cout << "A::memfunc(void)\n";
    }
};

template< typename T >
struct SubNoTypename : protected Base< T > {
    using Base< T >::Base;
    using Base< T >::member;
    using Base< T >::memfunc;
    using Base< T >::Ttype;  // n.b. no error in clang++
};

template< typename T >
struct SubTypename : protected Base< T > {
    using typename Base< T >::Base;    // error in clang++
    using typename Base< T >::member;  // error in clang++
    using typename Base< T >::memfunc; // error in clang++
    using typename Base< T >::Ttype;
};

и SubNoTypename и SubTypename признаны стандартными соответствующими gcc. С другой стороны, clang++ жалуется в SubTypename о malplaced typename ключевые слова. Однако это даже не согласуется, потому что тогда он должен жаловаться на отсутствие typename на using Base< T >::Ttype;. Это явно клоп.


редактировать The typename ключевое слово также разрешено, если базовый класс не является классом шаблона, место, где обычно вы никогда не ожидали бы, что это ключевое слово будет действительным:

class BaseNoTemplate {
  protected:
    typedef T Ttype;
    Ttype member;

  public:
    BaseNoTemplate() {
        std::cout << "A::A()\n";
    }
    BaseNoTemplate(const char *) {
        std::cout << "A::A(const char *)\n";
    }

    void memfunc(void) {
        std::cout << "A::memfunc(void)\n";
    }
};

struct SubNoTemplateNoTypename : protected BaseNoTemplate {
    using BaseNoTemplate::BaseNoTemplate;
    using BaseNoTemplate::member;
    using BaseNoTemplate::memfunc;
    using BaseNoTemplate::Ttype;
};

struct SubNoTemplateTypename : protected BaseNoTemplate {
    using typename BaseNoTemplate::BaseNoTemplate; // error in clang++
    using typename BaseNoTemplate::member;  // error in clang++
    using typename BaseNoTemplate::memfunc; // error in clang++
    using typename BaseNoTemplate::Ttype;   // n.b. no error in clang++
};

Извините, почему вы хотите using, почему не просто typedef?

template <typename T>
class Sub : public Base<T>
{
    typedef Base<T> Base;
};