Ошибка "разработанный тип относится к typedef" при попытке подружиться с typedef
Допустим, у меня есть следующий фрагмент кода (простая иерархия классов CRTP). Я хочу определить тип базового класса, чтобы сохранить типизацию (в моем реальном коде я использую тип базового класса более одного раза, а базовый класс принимает несколько параметров шаблона), и мне нужно подружиться с базовым классом, так как я хочу сохранить реализация частная.
template< class D >
class Base
{
public:
void foo() { *static_cast< D * >(this)->foo_i(); }
};
template< class T >
class Derived : public Base< Derived< T > >
{
public:
typedef class Base< Derived< T > > BaseType;
private:
// This here is the offending line
friend class BaseType;
void foo_i() { std::cout << "foo\n"; }
};
Derived< int > crash_dummy;
лязг говорит:
[...]/main.cpp:38:22: error: elaborated type refers to a typedef
friend class BaseType;
^
[...]/main.cpp:33:44: note: declared here
typedef class Base< Derived< T > > BaseType;
Как это исправить? Я заметил, что могу просто напечатать все это только для объявления класса друга, и оно отлично работает, но даже небольшой дублированный код заставляет меня чувствовать себя немного неловко, поэтому я ищу более элегантное "правильное" решение,
4 ответа
Я считаю, что это невозможно с C++03, но был добавлен к C++11, в котором вы можете просто опустить class
ключевое слово:
friend BaseType;
Включите только C++11 и используйте friend BaseType
Вы не можете использовать класс друга на typedef в C++03.
Разработанный спецификатор типа должен использоваться в объявлении друга для класса (101)
101) Требуется ключ класса разработанного спецификатора типа.
elaborated-type-specifier:
class-key ::opt nested-name-specifieropt identifier
class-key ::opt nested-name-specifieropt templateopt template-id
enum ::opt nested-name-specifieropt identifier
typename ::opt nested-name-specifier identifier
typename ::opt nested-name-specifier templateopt template-id
На самом деле вы можете сделать это в C++ раньше, чем в C++11, но для этого требуется довольно сложный (ха-ха) обходной путь, аналогично тому, как 1st объявите этот "помощник":
template< class T > struct ParamTypeStruct { typedef T ParamType; };
Тогда ваше заявление друга:
friend class ParamTypeStruct< BaseType >::ParamType;
(Я хотел прокомментировать ответ пользователя user2793784 и подписался на Stackru, но у меня недостаточно репутации, чтобы комментировать...)
К сожалению, его обходной путь ParamTypeStruct не работает для меня, используя clang; он по-прежнему жалуется, что "разработанный тип относится к typedef". Видимо, компилятор достаточно "умен", чтобы обнаружить этот трюк.