язык юрист — 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 *)

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

13

Решение

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

используя декларацию:

используя typename_opt nested-name-specier unqualified-id;

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

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 о неуместных typename ключевые слова. Тем не менее, это даже не соответствует, потому что он должен потом жаловаться на пропавших без вести typename в using Base< T >::Ttype;, Это явно ошибка лягушки.


редактировать
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++
};
2

Другие решения

Извини зачем ты хочешь usingпочему бы просто typedef?

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

По вопросам рекламы [email protected]