4

タイプを1つずつ追加して、コンパイル時にタイプのリスト(実際にはセット)を組み立てたいと思います。このようなもの:

struct HeadOfList;

struct Item1;
[ addToList<Item1, HeadOfList> ]

struct Item2;
[ addToList<Item2, HeadOfList> ]

リストの保存方法は気にしません。私はこのようなことを考えています:

template<typename T> struct NextInList { typedef void type; };
template<> struct NextInList<HeadOfList> { typedef Item1 type; };
template<> struct NextInList<Item1> { typedef Item2 type; };
template<> struct NextInList<Item2> { typedef Item3 type; };

しかし、aboost::mpl::listも同様に問題ありません。タイプの順序も重要ではありません。それらを繰り返し処理して、新しい要素を追加できるようにしたいだけです。

LastElementOf<MyList>::typeこのような構成は、たとえば、ソース ファイルのさまざまなポイント (新しい要素を追加する前後) でさまざまな型にコンパイルされることを意味するため、これについては悪い予感がします。それにもかかわらず、それはまさに私が今欲しいものです。

なんとなく可能だと思いませんか?C++11 が許可されています。

更新:新しい要素を追加するときにリストに追加された最後の要素がわからないことを追加したいだけですが、リスト自体は知っています(たとえば、リストの先頭)

4

1 に答える 1

5

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)
于 2012-06-17T20:32:49.990 に答える