comp.lang.c++.moderated と相談した後、以下に詳述するコードを思いつきました。PushBack()
マクロはリストに新しいアイテムを追加するために使用され、マクロを使用してアイテムを反復処理でき、Next()
最後のアイテムはその「次のアイテム」がそれ自体であることから認識できます。非常に基本的なコード例:
struct A {};
namespace NS1 {
struct B {};
struct C {};
struct D {};
// building up the compile-time list
struct Head;
PushBack(Head, A);
PushBack(Head, B);
}
PushBack(NS1::Head, NS1::C);
namespace NS1 {
PushBack(Head, D);
}
// iterate through the list
namespace NS2 {
// end of the list reached (recognized from PrevItem == Item)
template <class ListId, class Item>
void print(Wrapper<Item>, Wrapper<Item>) {}
// process Item and advance to the next element
template <class ListId, class PrevItem, class Item>
void print(Wrapper<PrevItem>, Wrapper<Item>)
{
cout << typeid(Item).name() << endl;
print<ListId>(Wrapper<Item>(), Wrapper< Next(ListId, Item) >());
}
}
リストの使用を容易にするイテレータも含む、より詳細な例については、こちらまたはこちらを参照してください。
「ライブラリ」の最も重要な部分:
/// Helper class to wrap incomplete types and avoid instantiation of T
template<class T> struct Wrapper {};
namespace CTList {
/// The front of compile-time lists
struct Nil {};
}
/// Compile-time list helper
template< typename ListId, typename Item >
Item NextInListHelper( ::Wrapper<ListId>, ::Wrapper<Item> );
/// The last element of the list
#define Back(ListId) \
decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
CTList::Nil \
>())) \
>())) \
>())) \
>())) \
>())) \
>())) \
>())) \
>())) \
>())) \
>()))
/// Add a new element (type) to the list
#define PushBack( ListId, item) \
item NextInListHelper( ::Wrapper< ListId >, ::Wrapper< Back(ListId) > )
/// The next element in the ('ListId') list after 'item'
#define Next(ListId, item) decltype(NextInListHelper(::Wrapper<ListId>(), ::Wrapper<item>() ))
NextInListHelper
関数宣言と Argument Dependent (Name)Look-up を使用してリストを記録します。Back
リストの最後の要素は、マクロを使用して参照できます。
リストの最初の要素は としてアクセスでき、リストNext(ListId, CTList::Nil)
の最後の要素は次の要素 ( ) と同じであることから認識できますLastItem == Next(ListId, LastItem)
。
gcc 4.6.3 でのみテストしましたが、C++11 に完全に準拠することを意図しています。
ソリューションに関するいくつかの言葉:
Back()
この形式では、最大 10 個の要素の型リストを処理できますが、これはマクロに余分な行を追加することで拡張できます
- 「リスト」にはタイプを一度だけ含めることができます
ListId
宣言で使用される追加の型NextInListHelper
は、型を複数のリストに同時に含めることができるようにするためのものです
Wrapper
リスト要素タイプの実際のインスタンス化を回避し、不完全なタイプを ListId としてサポートするために使用されます
PushBack()
'calls' はListId
( NS1
) またはWrapper
(グローバル スコープ)の名前空間にある必要があります
- リストの処理は任意の名前空間に入れることができます (
NS2
)