Слишком поздно играть?
Учитывая список X1
- X8
функций, я предлагаю добавить шаблон класса, который отображает число от 0 до 7 в классы X1
- X8
и наследовать от X1
- X8
, только если первый логический параметр шаблона имеет вид true
template <bool, std::size_t>
struct Feature
{ };
template <> struct Feature<true, 0> : public X1 { };
template <> struct Feature<true, 1> : public X2 { };
template <> struct Feature<true, 2> : public X3 { };
template <> struct Feature<true, 3> : public X4 { };
template <> struct Feature<true, 4> : public X5 { };
template <> struct Feature<true, 5> : public X6 { };
template <> struct Feature<true, 6> : public X7 { };
template <> struct Feature<true, 7> : public X8 { };
Теперь структура Feature_helper
, которая наследует право Feature
для каждого бита в std::uint8_t
число, просто
template <std::uint8_t, typename = std::make_index_sequence<8u>>
struct Feature_helper;
template <std::uint8_t u8, std::size_t ... Is>
struct Feature_helper<u8, std::index_sequence<Is...>>
: public Feature<(u8 & (1 << Is)) != 0u, Is>...
{ };
и A
становятся
template <std::uint8_t u8>
class A : public Feature_helper<u8>
{ };
Ниже приведен полный пример компиляции
#include <cstdint>
#include <utility>
#include <type_traits>
struct X1 { };
struct X2 { };
struct X3 { };
struct X4 { };
struct X5 { };
struct X6 { };
struct X7 { };
struct X8 { };
template <bool, std::size_t>
struct Feature
{ };
template <> struct Feature<true, 0> : public X1 { };
template <> struct Feature<true, 1> : public X2 { };
template <> struct Feature<true, 2> : public X3 { };
template <> struct Feature<true, 3> : public X4 { };
template <> struct Feature<true, 4> : public X5 { };
template <> struct Feature<true, 5> : public X6 { };
template <> struct Feature<true, 6> : public X7 { };
template <> struct Feature<true, 7> : public X8 { };
template <std::uint8_t, typename = std::make_index_sequence<8u>>
struct Feature_helper;
template <std::uint8_t u8, std::size_t ... Is>
struct Feature_helper<u8, std::index_sequence<Is...>>
: public Feature<(u8 & (1 << Is)) != 0u, Is>...
{ };
template <std::uint8_t u8>
class A : public Feature_helper<u8>
{ };
int main()
{
static_assert( true == std::is_base_of_v<X1, A<5u>> );
static_assert( false == std::is_base_of_v<X2, A<5u>> );
static_assert( true == std::is_base_of_v<X3, A<5u>> );
static_assert( false == std::is_base_of_v<X4, A<5u>> );
static_assert( false == std::is_base_of_v<X5, A<5u>> );
static_assert( false == std::is_base_of_v<X6, A<5u>> );
static_assert( false == std::is_base_of_v<X7, A<5u>> );
static_assert( false == std::is_base_of_v<X8, A<5u>> );
}
- - РЕДАКТИРОВАТЬ -
Наблюдать за OP
Обнаружил обратную сторону, наследование класса Feature_helper
не будет прямым производным классом Feature
. Это означает, что он не может наследовать конструкторы от X1
, X2
, ...
Не уверен, что понял ваше требование, но я полагаю, вы можете решить проблему (если между * 1040 нет коллизии * construnctors) с использованием большого числа using
.
В следующем примере я добавил конструктор int
для X1
и конструктор long
для X2
.
Обратите внимание на X1() = default;
и X2() = default;
: при добавлении явного конструктора конструкторы / деструкторы по умолчанию удаляются; поэтому вы должны заново установить их по умолчанию (возможно, также скопировать / переместить конструкторы).
#include <cstdint>
#include <utility>
#include <iostream>
#include <type_traits>
struct X1 { X1(int) { std::cout << "X1 constructor" << std::endl; }
X1() = default; };
struct X2 { X2(long) { std::cout << "X2 constructor" << std::endl; }
X2() = default; };
struct X3 { };
struct X4 { };
struct X5 { };
struct X6 { };
struct X7 { };
struct X8 { };
template <bool, std::size_t>
struct Feature
{ };
template <> struct Feature<true, 0> : public X1 { using X1::X1; };
template <> struct Feature<true, 1> : public X2 { using X2::X2; };
template <> struct Feature<true, 2> : public X3 { };
template <> struct Feature<true, 3> : public X4 { };
template <> struct Feature<true, 4> : public X5 { };
template <> struct Feature<true, 5> : public X6 { };
template <> struct Feature<true, 6> : public X7 { };
template <> struct Feature<true, 7> : public X8 { };
template <std::uint8_t, typename = std::make_index_sequence<8u>>
struct Feature_helper;
template <std::uint8_t u8, std::size_t ... Is>
struct Feature_helper<u8, std::index_sequence<Is...>>
: public Feature<(u8 & (1 << Is)) != 0u, Is>...
{ using Feature<(u8 & (1 << Is)) != 0u, Is>::Feature...; };
template <std::uint8_t u8>
class A : public Feature_helper<u8>
{ using Feature_helper<u8>::Feature_helper; };
int main()
{
static_assert( true == std::is_base_of_v<X1, A<5u>> );
static_assert( false == std::is_base_of_v<X2, A<5u>> );
static_assert( true == std::is_base_of_v<X3, A<5u>> );
static_assert( false == std::is_base_of_v<X4, A<5u>> );
static_assert( false == std::is_base_of_v<X5, A<5u>> );
static_assert( false == std::is_base_of_v<X6, A<5u>> );
static_assert( false == std::is_base_of_v<X7, A<5u>> );
static_assert( false == std::is_base_of_v<X8, A<5u>> );
A<3u> a1(1); // call the X1(int) constructor
A<3u> a2(2l); // call the X2(long) constructor
}