C ++ статическая диспетчеризация с пользовательской инициализацией - PullRequest
0 голосов
/ 26 февраля 2019

Я хотел бы использовать CRTP для чувствительного к производительности раздела моего кода.Тем не менее, мой базовый класс имеет набор битов, размер которого зависит от производного класса.Я надеялся, что что-то подобное сработает:

template <typename Derived>
class Base {
protected:
    std::bitset<Derived::bsize> data_;
};

class Foo : public Base<Foo> {
public:
    constexpr static size_t bsize = 2;
};

, но компилятор жалуется: "нет члена bsize в Foo".Полагаю, что я мог бы решить мою проблему, тоже задав шаблонную длину набора битов в базовом классе:

template <typename Derived, size_t size>
class Base {
protected:
    std::bitset<size> data_;
};

class Foo : public Base<Foo,2> { ... };

В будущем я мог бы захотеть использовать более сложные выражения для вычисления длины набора битов.Есть ли способ выполнить работу, используя функции constexpr?(ближе по духу к моему первому нерабочему решению) Спасибо.

1 Ответ

0 голосов
/ 26 февраля 2019

Ответ: вы не можете сделать это с CRTP в C ++.Что происходит, когда создается экземпляр Base<Foo>, Foo::bsize еще не существует.Это происходит потому, что это происходит, когда компилятор видит Base<Foo> в классе Foo, который находится перед вашим {.Это не совсем так просто, но это общая идея.

Есть обходной путь, чтобы сделать то, что вы хотите здесь, то есть объединить всю необходимую информацию в классе, затемпредоставить его в качестве параметра шаблона.Я не знаю названия этого паттерна (я видел «класс багажа», но это кажется уничижительным), но вы можете найти примеры этого в стандартной библиотеке, такой как std::char_traits.

class FooTraits {
    constexpr static size_t bsize = 2;
};

template <class Traits = FooTraits>
class BasicFoo {
protected:
    std::bitset<Traits::bsize> data_;
};

Черты довольно гибкие - вы можете просто вставить функцию static constexpr в свой FooTraits, чтобы вычислить все, что вам нужно.В вашем случае производный класс будет передавать специфичную для производного типа версию FooTraits аргументу шаблона Traits, равному BasicFoo.

Стоит отметить, что ваш milage может отличаться.Несмотря на гибкость, проблема с чертами заключается в том, что кто-то, желающий реализовать концепцию FooTraits, должен убедиться, что он реализует все, что нужно BasicFoo, иначе он получит ужасную ошибку компиляции (в C ++ 20 это помогаетчерез понятия ).Без тщательного обдумывания черты могут стать местом свалки, что делает реализацию альтернативы FooTraits еще сложнее.

...