C++ 基于非类型参数值推断类型列表

C++ 基于非类型参数值推断类型列表,c++,c++17,metaprogramming,crtp,C++,C++17,Metaprogramming,Crtp,我有一个类,可以在可变模板参数中使用未定义数量的策略进行自定义: 模板 A类:公共特征。。。{}; 所述功能通过constexpr uint8\t的位启用,例如: 0x1 --> X1 enabled 0x2 --> X2 enabled 0x3 --> X1, X2 enabled 0x4 --> X3 enabled 0x5 --> X1, X3 enabled etc... 如何编写帮助器类型来推断正确的类型列表并将其转发到类A的可变模板参数 使用std:

我有一个类,可以在可变模板参数中使用未定义数量的策略进行自定义:

模板
A类:公共特征。。。{};
所述功能通过
constexpr uint8\t
的位启用,例如:

0x1 --> X1 enabled
0x2 --> X2 enabled
0x3 --> X1, X2 enabled
0x4 --> X3 enabled
0x5 --> X1, X3 enabled
etc...
如何编写帮助器类型来推断正确的类型列表并将其转发到
类A
的可变模板参数

使用
std::conditional
我可以写这样的东西,但正如你所能想象的那样,它会很快变得可怕


使用ExtendedA=A将您的标志转换为特性的集合(元组),您可以使用类似以下代码:

template <std::size_t> struct Feature;

template <> struct Feature<0> { using type = X0; };
template <> struct Feature<1> { using type = X1; };
template <> struct Feature<2> { using type = X2; };
template <> struct Feature<3> { using type = X3; };
template <> struct Feature<4> { using type = X4; };
template <> struct Feature<5> { using type = X5; };
// ...
constexpr std::size_t FeaturesCount = /*..*/;

template <std::size_t Flag, std::size_t...Is>
auto CollectFeaturesImpl(std::index_sequence<Is...>)
-> decltype(std::tuple_cat(
       std::conditional_t<
           (Flag & (1U << Is)) != 0,
           std::tuple<typename Feature<Is>::type>,
           std::tuple<>>
       {}...
   ))

template <std::size_t Flag>
using CollectFeatures_t =
    decltype(CollectFeaturesImpl<Flag>(std::make_index_sequence<FeaturesCount>()));

模板结构FromTuple;
模板
struct FromTuple
{
模板
使用map=C;
};
使用myA=FromTuple::map;//A.
玩得太晚了吗

给定一个特性列表
X1
-
X8
,我建议添加一个模板类,该模板类将数字从0映射到7到类
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 { };
A
成为

template <std::uint8_t u8>
class A : public Feature_helper<u8>
 { };

您可能可以。非常有趣,除非我弄错了,否则我使用的唯一警告(但这方面的问题具有误导性)是您编写的收集器需要
::键入为序列中的每个值定义的
。但是我可以通过添加一个额外的特征和一个额外的签入
std::conditional
来解决这个问题。非常感谢!您仍然可以使用别名:
模板使用Feature\u t=typename Feature::type…玩游戏永远不会太迟!我想我更喜欢你的解决方案,它依赖于更简单的机制,更具可读性。它也不需要更多的东西来“跳过”功能之间未使用的部分。这一次我学到了很多,谢谢!发现了一个缺点,继承
功能的类\u helper
将不是功能的直接派生类。这意味着它不能从
X1
X2
,…@Fluffy-Yes>继承构造函数。。。但是我想你可以用
解决这个问题。答案有所改善。
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>
 { };
#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>> );
 }
#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
 }