Ошибка "разработанный тип относится к 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". Видимо, компилятор достаточно "умен", чтобы обнаружить этот трюк.

Другие вопросы по тегам