我正在阅读 Andrei Alexandrescu 的《现代 C++ 设计》,我正在尝试使用他提供的一些类型列表示例。在下面的示例中,我想创建一个 Option
结构列表,其中包含一个类型和一个整数。稍后我想创建这些选项的类型列表,然后将其与一个整数一起传递给另一个结构 FindTypeForMapping
。如果整数与选项列表中设置的任何整数匹配,则表达式应计算为该选项的类型,否则应计算为我的自定义类型 NullType
。
第一种可行的方法是 OptionsList
是用宏创建的,并且我为列表中包含的每个 Option
数量都有宏,其中每个宏用于n
Option
s 正在使用 n-1
Option
s 的宏。
然后我想用模板中的一个参数包来参数列表。此版本的列表名为 OptionsList2
。在 OptionsList2
中,我以递归方式构建列表,但随后在将此列表传递给 FindTypeForMapping
时出现编译时错误(见下文)。
struct NullType { };
template<class T, class U>
struct OptionsList
{
typedef T Head;
typedef U Tail;
};
template<class T, class... U>
struct OptionsList2
{
typedef T Head;
typedef typename std::conditional<sizeof...(U) == 0, NullType, OptionsList2<U...>>::type Tail;
};
template<int n, typename N>
struct Option
{
enum {
int_mapping = n
};
typedef N MappedType;
};
template<int, int> struct CheckMappedInt;
template<int n>
struct CheckMappedInt<n, n>
{
enum { is_the_same = 1};
};
template<int n, int m>
struct CheckMappedInt
{
enum { is_the_same = 0};
};
template<typename OLT, int n> struct FindTypeForMapping;
template<int n>
struct FindTypeForMapping<NullType, n>
{
typedef NullType mapped_type;
};
template<typename OP, typename Tail, int n>
struct FindTypeForMapping<OptionsList<OP, Tail>, n>
{
private:
enum {temp = CheckMappedInt<OP::int_mapping, n>::is_the_same };
typedef typename FindTypeForMapping<Tail, n>::mapped_type temp_type;
public:
typedef typename std::conditional<
temp == 1,
typename OP::MappedType,
temp_type>::type mapped_type;
};
// Added this after SoryTellers comment
template<typename OP, typename Tail, int n>
struct FindTypeForMapping<OptionsList2<OP, Tail>, n>
{
private:
enum {temp = CheckMappedInt<OP::int_mapping, n>::is_the_same };
typedef typename FindTypeForMapping<Tail, n>::mapped_type temp_type;
public:
typedef typename std::conditional<
temp == 1,
typename OP::MappedType,
temp_type>::type mapped_type;
};
#define OPTION_LIST_1(op1) OptionsList<op1, NullType>
#define OPTION_LIST_2(op1, op2) OptionsList<op1, OPTION_LIST_1(op2)>
#define OPTION_LIST_3(op1, op2, op3) OptionsList<op1, OPTION_LIST_2(op2, op3)>
#define OPTION_LIST_4(op1, op2, op3, op4) OptionsList<op1, OPTION_LIST_3(op2, op3, op4)>
#define OPTION_LIST_5(op1, op2, op3, op4, op5) OptionsList<op1, OPTION_LIST_4(op2, op3, op4, op5)>
#define OPTION_LIST_6(op1, op2, op3, op4, op5, op6) OptionsList<op1, OPTION_LIST_5(op2, op3, op4, op5, op6)>
#define OPTION_LIST_7(op1, op2, op3, op4, op5, op6, op7) OptionsList<op1, OPTION_LIST_6(op2, op3, op4, op5, op6, op7)>
#define OPTION_LIST_8(op1, op2, op3, op4, op5, op6, op7, op8, op9) OptionsList<op1, OPTION_LIST_7(op2, op3, op4, op5, op6, op7, op8)>
#define OPTION_LIST_9(op1, op2, op3, op4, op5, op6, op7, op8, op9) OptionsList<op1, OPTION_LIST_8(op2, op3, op4, op5, op6, op7, op8, op9)>
int main(int argc, char* argv[])
{
typedef Option<1, char> o1;
typedef Option<2, int> o2;
// Works
typedef OPTION_LIST_2(o1, o2) ol;
typedef typename FindTypeForMapping<ol, 1>::mapped_type ResolvedType; // Works
typedef OptionsList2<o1, o2> ol2;
typedef typename FindTypeForMapping<ol2, 1>::mapped_type ResolvedType2;
/*
error: invalid use of incomplete type ‘struct FindTypeForMapping<Option<2, int>, 1>’
typedef typename FindTypeForMapping<Tail, n>::mapped_type temp_type;
*/
}
最佳答案
抱歉,但是......你为什么不简单地使用 std::tuple
而不是可变参数 OptionList2
?
您的 FindTypeForMapping
类型特征可以简单地写成(抱歉,如果我在 FTFM
中缩短名称)
template <typename, int>
struct FTFM;
template <int n, int no, typename TypeO, typename ... Ts>
struct FTFM<std::tuple<Option<no, TypeO>, Ts...>, n>
{ using type = typename FTFM<std::tuple<Ts...>, n>::type; };
template <int n, typename TypeO, typename ... Ts>
struct FTFM<std::tuple<Option<n, TypeO>, Ts...>, n>
{ using type = TypeO; };
template <int n>
struct FTFM<std::tuple<>, n>
{ using type = NullType; };
下面是一个完整的工作(嗯......编译)示例
#include <tuple>
#include <type_traits>
struct NullType
{ };
template <int n, typename T>
struct Option : public std::integral_constant<int, n>
{ using type = T; };
template <typename, int>
struct FTFM;
template <int n, int no, typename TypeO, typename ... Ts>
struct FTFM<std::tuple<Option<no, TypeO>, Ts...>, n>
{ using type = typename FTFM<std::tuple<Ts...>, n>::type; };
template <int n, typename TypeO, typename ... Ts>
struct FTFM<std::tuple<Option<n, TypeO>, Ts...>, n>
{ using type = TypeO; };
template <int n>
struct FTFM<std::tuple<>, n>
{ using type = NullType; };
template <typename T, int I>
using FTFM_t = typename FTFM<T, I>::type;
int main ()
{
using opt0 = Option<0, void>;
using opt1 = Option<1, char>;
using opt2 = Option<2, short>;
using opt3 = Option<3, int>;
using opt4 = Option<4, long>;
using opt5 = Option<5, long long>;
using optList = std::tuple<opt0, opt1, opt2, opt3, opt4, opt5>;
static_assert ( std::is_same<void, FTFM_t<optList, 0>>{}, "!" );
static_assert ( std::is_same<char, FTFM_t<optList, 1>>{}, "!" );
static_assert ( std::is_same<short, FTFM_t<optList, 2>>{}, "!" );
static_assert ( std::is_same<int, FTFM_t<optList, 3>>{}, "!" );
static_assert ( std::is_same<long, FTFM_t<optList, 4>>{}, "!" );
static_assert ( std::is_same<long long, FTFM_t<optList, 5>>{}, "!" );
static_assert ( std::is_same<NullType, FTFM_t<optList, 6>>{}, "!" );
}
关于c++ - 使用模板参数包代替宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46636219/