在C ++中递增地构建编译时间列表 [英] Building a compile time list incrementally in C++

查看:225
本文介绍了在C ++中递增地构建编译时间列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C ++中,是否有一种以递增方式构建编译时间列表的方法,以下列模式?

  START_LIST )
ADD_TO_LIST(List,int)
ADD_TO_LIST(List,float)
ADD_TO_LIST(List,double)
END_LIST(List)

此结果应等同于:

  using List = Cons< int,Cons< float,Cons< double,Nil>>>> 

我也有一个限制,宏之间的空间需要在任何范围。我打算定义的东西,并使用一个宏,同时在列表中注册它们,像这样:

 #使用Name = SomeTemplate< Value> ;;定义DEFINE_ELEMENT(名称,值)\ 
\
ADD_TO_LIST(ListOfElements,Name)

换句话说,将 START_LIST 定义为 SomeTemplate decltype(。这将使得不可能在其中添加新的定义。



注意,解决方案可以是参数包(可变参数模板)列表的形式。只要注意它遵循如上所示的增量定义模式。



可以在这里使用特殊化吗?如果不可能完全与上述模式,是可能有一点更多样板?

解决方案

在OP自己的解决方案中,它只适用于全局范围,不适用于类范围,这里适用于所有的全局,类和函数范围。与OP的解决方案相比的另一个优点是我的解决方案允许多个列表START_LIST / END_LIST对重叠,即不同的列表构造可以交错。



<一个小的限制是它使用 __ COUNTER __ 宏,它不是starndard的一部分,但它被gcc,clang和MSVC很好地支持,因此可移植性不是一个大问题这里。另一件事是对于函数范围,它必须使用一个单独的宏 START_LIST_FUNC ADD_TO_LIST_FUNC ,因为我使用函数重载分辨率但在函数范围内它不能声明 static 函数,而在类级别它必须使用 static 函数。 / p>

编辑:结合OP的注释ListReverseHelper的想法,使它更简单。

  #include< iostream> 
#include< typeinfo>
using namespace std;

struct Nil {};

template< typename T,typename U> struct Cons {};

template< typename List,typename Reversed> struct ListReverseHelper;

template< typename Reversed>
struct ListReverseHelper< Nil,Reversed> {
using Type = Reversed;
};

template< typename Head,typename Tail,typename Reversed>
struct ListReverseHelper< Cons< Head,Tail>,Reversed> {
using Type = typename ListReverseHelper< Tail,Cons< Head,Reversed>> :: Type;
};

template< typename T,int N> struct ListMakerKey:ListMakerKey< T,N-1> {};
template< typename T> struct ListMakerKey< T,0> {};

#define START_LIST_(name,modifier)\
struct name ## _ ListMaker {}; \
modifier Nil list_maker_helper_(ListMakerKey< name ## _ ListMaker,__COUNTER __>);
#define ADD_TO_LIST_(name,type,modifier)\
modifier Cons< type,decltype(list_maker_helper_(ListMakerKey< name ## _ ListMaker,__COUNTER __> {}))> \
list_maker_helper_(ListMakerKey< name ## _ ListMaker,__COUNTER __>);
#define END_LIST(name)\
using name = typename ListReverseHelper< decltype(list_maker_helper_(ListMakerKey< name ## _ ListMaker,__COUNTER __> {})),Nil&

#define START_LIST(name)START_LIST_(name,static)
#define ADD_TO_LIST(name,type)ADD_TO_LIST_(name,type,static)
#define START_LIST_FUNC START_LIST_(name,)
#define ADD_TO_LIST_FUNC(name,type)ADD_TO_LIST_(name,type)

START_LIST(List)
ADD_TO_LIST(List,int)
int a = 10;
ADD_TO_LIST(List,float)
int b = 10;
START_LIST(List2)
ADD_TO_LIST(List,int)
int c = 10;
ADD_TO_LIST(List2,float)
ADD_TO_LIST(List,double)
ADD_TO_LIST(List2,int)
ADD_TO_LIST(List2,float)
END_LIST $ b ADD_TO_LIST(List,double)
ADD_TO_LIST(List,char)
END_LIST(List)

struct A {
START_LIST(List3)
ADD_TO_LIST (List3,int)
int a = 10;
ADD_TO_LIST(List3,float)
int b = 10;
ADD_TO_LIST(List3,double)
ADD_TO_LIST(List3,int)
END_LIST(List3)
};

int main(){
START_LIST_FUNC(List4)
ADD_TO_LIST_FUNC(List4,char)
int a = 10;
ADD_TO_LIST_FUNC(List4,float)
int b = 10;
ADD_TO_LIST_FUNC(List4,int)
ADD_TO_LIST_FUNC(List4,char)
END_LIST(List4)
List x;
List2 y;
A :: List3 z;
List4 w;
cout<< typeid(x).name()<< endl;
cout<< typeid(y).name()<< endl;
cout<< typeid(z).name()<< endl;
cout<< typeid(w).name()<< endl;
}

在g ++ - 4.8下编译:

  [hidden] $ g ++ -std = c ++ 11 x.cpp&& c ++ filt -t`。/ a.out` 
Cons< int,Cons< float,Cons< int,Cons< double,Cons< double,Cons< char,Nil> > > > > >
Cons< float,Cons< int,Cons< float,Nil> > >
Cons< int,Cons< float,Cons< double,Cons< int,Nil> > > >
Cons< char,Cons< float,Cons< int,Cons< char,Nil> > > >


In C++, is there a way to build a compile time list incrementally, in the following pattern?

START_LIST(List)
ADD_TO_LIST(List, int)
ADD_TO_LIST(List, float)
ADD_TO_LIST(List, double)
END_LIST(List)

The result of this should be equivalent to:

using List = Cons<int, Cons<float, Cons<double, Nil>>>;

I also have a restriction that the space between the macros needs to be at whatever scope the whole thing is. I'm planning to define things and register them with the list at the same time using a macro, something like this:

#define DEFINE_ELEMENT(Name, Value) \
using Name = SomeTemplate<Value>; \
ADD_TO_LIST(ListOfElements, Name)

In other words, it is not permitted to define START_LIST to something like SomeTemplate< or decltype(. That would make it impossible to add new definitions in between.

Note that the solution can alternatively be in the form of a "parameter pack" (variadic template) list. I only care that it follows the incremental definition pattern as shown above.

Could specializations be used here? If it's not possible exactly with the above pattern, is it possible with a bit more boilerplate?

解决方案

In OP's own solution, it only works for global scope, not class scope, nor function scope. My implementation here works for all of global, class and function scope. Another advantage over OP's solution is my solution allow multiple list START_LIST/END_LIST pairs overlap, i.e. different list constructions can be interleaving.

One small limitation is it uses __COUNTER__ macro, which is not part of starndard, but it is well supported by gcc, clang and MSVC, so portability is not a big issue here. Another thing is for function scope, it has to use a separate macro START_LIST_FUNC and ADD_TO_LIST_FUNC as I make use function overload resolution but in function scope it can't declare static function, while at class level it has to use static function.

EDIT: incorporate the idea of ListReverseHelper from OP's comment to make it much simpler.

#include <iostream>
#include <typeinfo>
using namespace std;

struct Nil {};

template <typename T, typename U> struct Cons {};

template <typename List, typename Reversed> struct ListReverseHelper;

template <typename Reversed>
struct ListReverseHelper<Nil, Reversed> {
  using Type = Reversed;
};

template <typename Head, typename Tail, typename Reversed>
struct ListReverseHelper<Cons<Head, Tail>, Reversed> {
  using Type = typename ListReverseHelper<Tail, Cons<Head, Reversed>>::Type;
};

template <typename T, int N> struct ListMakerKey : ListMakerKey<T, N-1> {};
template <typename T> struct ListMakerKey<T, 0> {};

#define START_LIST_(name, modifier) \
  struct name##_ListMaker {}; \
  modifier Nil list_maker_helper_(ListMakerKey<name##_ListMaker, __COUNTER__>);
#define ADD_TO_LIST_(name, type, modifier) \
  modifier Cons<type, decltype(list_maker_helper_(ListMakerKey<name##_ListMaker, __COUNTER__>{}))> \
  list_maker_helper_(ListMakerKey<name##_ListMaker, __COUNTER__>);
#define END_LIST(name) \
  using name = typename ListReverseHelper<decltype(list_maker_helper_(ListMakerKey<name##_ListMaker, __COUNTER__>{})), Nil>::Type;

#define START_LIST(name) START_LIST_(name, static)
#define ADD_TO_LIST(name, type) ADD_TO_LIST_(name, type, static)
#define START_LIST_FUNC(name) START_LIST_(name,)
#define ADD_TO_LIST_FUNC(name, type) ADD_TO_LIST_(name, type,)

START_LIST(List)
ADD_TO_LIST(List, int)
int a = 10;
ADD_TO_LIST(List, float)
int b = 10;
START_LIST(List2)
ADD_TO_LIST(List, int)
int c = 10;
ADD_TO_LIST(List2, float)
ADD_TO_LIST(List, double)
ADD_TO_LIST(List2, int)
ADD_TO_LIST(List2, float)
END_LIST(List2)
ADD_TO_LIST(List, double)
ADD_TO_LIST(List, char)
END_LIST(List)

struct A {
  START_LIST(List3)
  ADD_TO_LIST(List3, int)
  int a = 10;
  ADD_TO_LIST(List3, float)
  int b = 10;
  ADD_TO_LIST(List3, double)
  ADD_TO_LIST(List3, int)
  END_LIST(List3)
};

int main() {
  START_LIST_FUNC(List4)
  ADD_TO_LIST_FUNC(List4, char)
  int a = 10;
  ADD_TO_LIST_FUNC(List4, float)
  int b = 10;
  ADD_TO_LIST_FUNC(List4, int)
  ADD_TO_LIST_FUNC(List4, char)
  END_LIST(List4)
  List x;
  List2 y;
  A::List3 z;
  List4 w;
  cout << typeid(x).name() << endl;
  cout << typeid(y).name() << endl;
  cout << typeid(z).name() << endl;
  cout << typeid(w).name() << endl;
}

Compiled under g++-4.8:

[hidden]$ g++ -std=c++11 x.cpp && c++filt -t `./a.out`
Cons<int, Cons<float, Cons<int, Cons<double, Cons<double, Cons<char, Nil> > > > > >
Cons<float, Cons<int, Cons<float, Nil> > >
Cons<int, Cons<float, Cons<double, Cons<int, Nil> > > >
Cons<char, Cons<float, Cons<int, Cons<char, Nil> > > >

这篇关于在C ++中递增地构建编译时间列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆