С++ CRTP и доступ к производным вложенным typedefs из базы
изменить:. Я поставлю ссылку github здесь, когда я закончу изменение дизайна для всех, кто интересуется.
Фон
Я заменяю boost::intrusive
, intrusive_set
своей собственной реализацией в качестве 64-разрядных скомпилированных навязчивых наборов, содержащих 3 х 8-байтовых указателей в мои узлы контейнера. мой контейнер имеет ограничение на 2 ^ 16 узлов, поэтому я могу довести его до 4 байтов на node с 2x 16-битными ординалами смещения (что является уменьшением размера 6x).
В приведенном ниже примере base
- контейнер интрузивного набора. Класс derived
имеет std::vector<container_entry_type<entry_type> >
. очевидно, с этим уровнем косвенности мне нужно иметь кучу вложенных typedef в производных, которые я хотел бы ссылаться в базе.
p.s., контейнеры для АСТ языка описания данных. Таким образом, содержащиеся элементы представляют собой небольшие типы данных, и 3 x 8-байта очень значительны. Тем более, что контейнеры используются для проверки наборов данных в плотных циклах.
Проблема изолирована
Я хочу получить следующую семантику:
template<typename TWO>
class base
{
public:
void foo(typename TWO::dummy & d);
};
template<typename DUMMY>
class derived
: private base< derived<DUMMY> >
{
public:
typedef DUMMY dummy;
};
struct tag{};
int main()
{
derived<tag> foo;
}
Но я не могу получить доступ к вложенному typedef из базы. Это то, что clang должен сказать по этому поводу:
main.cc: In instantiation of ‘base<derived<tag> >’:
main.cc:9:7: instantiated from ‘derived<tag>’
main.cc:20:16: instantiated from here
main.cc:5:8: error: no type named ‘dummy’ in ‘class derived<tag>’
Вместо этого мне нужно сделать:
template<typename type_key>
class traits
{
public:
typedef type_key dummy;
};
template<typename TWO, typename type_key>
class base
{
public:
void foo(typename traits<type_key>::dummy & d);
};
template<typename DUMMY>
class derived
: private base< derived<DUMMY>, DUMMY >
{
public:
typedef DUMMY dummy;
};
struct tag{};
int main()
{
derived<tag> foo;
}
Это единственный способ добиться моего использования? это просто делает вещи намного более подробными. Я полагаю, что производный может также извлекаться из признаков, чтобы сохранить некоторые нажатия клавиш.
Другой выбор заключается в том, чтобы не использовать вывод и подключать логику прямо к тому, что в настоящее время происходит. Тем не менее, я хотел бы использовать индивидуально unit test base.
Ответы
Ответ 1
Другая возможность (которая может или не может сэкономить вам нажатия клавиш) не будет использовать вложенные типы производных классов в родительском объекте в некоторых местах. Например. вместо
void foo(typename TWO::dummy & d);
вы бы использовали
template <class T>
void foo(typename T& d);
Для дополнительных точек вы можете использовать SFINAE для фактического ограничения T
на типы, допустимые для исходного варианта. (Обратите внимание, что внутри вложенных шаблонов TWO::dummy
можно использовать свободно - они создаются только после того, как вся вещь, включая derived
, была выполнена, поэтому она работает. В наивной версии derived
все еще неполна в точке создания экземпляра base
с его функциями-членами, он не имеет ::dummy
, поэтому он терпит неудачу)
Ответ 2
Расширяя @jpalecek, мы могли бы сделать аргумент шаблона аргументом по умолчанию. Но вам нужно включить С++ 0x для получения этого
#include <typeinfo>
#include <cstdio>
template<typename TWO>
class base
{
public:
template <typename X = TWO> // <-- (requires C++0x to have a default)
void foo(typename X::dummy& d)
{
printf("%s\n", typeid(d).name());
}
};
template<typename DUMMY>
class derived
: public base< derived<DUMMY> >
{
public:
typedef DUMMY dummy;
};
struct tag{};
int main()
{
derived<tag> foo;
tag t;
foo.foo(t); // <--- call the function like normal.
}
http://ideone.com/AXXdW
Ответ 3
Нет необходимости в классе traits
. Вы можете просто использовать type_key
непосредственно в base
.
Однако вы не можете явно передать тип base
. В момент создания экземпляра base
параметр typedef в derived
еще не был замечен компилятором (точнее: класс derived
еще не завершен), как он мог, учитывая, что даже его базовый класс не существуют еще).