1

私はvariadicテンプレートリストにクラスのリストを持っているシナリオを実行しました。タイプ(Target_)を指定した場合、リスト内のクラス(ContainingClass_)はとしてContainingClass_::Classとなります。ここでC++で与えられた型のtypedefを持つ型リストから型を返すメタ関数を書く11

は私の現在、強引な実装である:

#include <iostream> 
#include <cstdlib> 
#include <type_traits> 
#include <tuple> 

template <uint32_t ID_, class Class_> 
struct ContainingClass 
{ 
    using Class = Class_; 
    static constexpr uint32_t id() { return ID_; } 
}; 

// Get the index of a type in a type list, or -1 on error (So that we only get the important static_assert). 
template <typename Target_, typename ...List_> 
struct IndexOf : std::integral_constant<int, -1> {}; 

template <typename Target_, typename NotTarget_, typename ...List_> 
struct IndexOf<Target_, NotTarget_, List_...> : std::integral_constant<std::size_t, 1 + IndexOf<Target_, List_...>::value> {}; 

template <typename Target_, typename ...List_> 
struct IndexOf<Target_, Target_, List_...> : std::integral_constant<std::size_t, 0> {}; 

// Check if a type exists in a typelist. 
template <typename Target_, typename... List_> 
struct TypeExists; 

template <typename Target_> 
struct TypeExists<Target_> : std::false_type {}; 

template <typename Target_, typename... List_> 
struct TypeExists<Target_, Target_, List_...> : std::true_type {}; 

template <typename Target_, typename NotTarget_, typename... List_> 
struct TypeExists<Target_, NotTarget_, List_...> : TypeExists<Target_, List_...> {}; 

// **THE META-FUNCTION THAT THE QUESTION IS ABOUT** 
// Find the ContaingClass that typedefs Target_ as "Class" inside of it. 
template <class Target_, class ...ContainingClasses_> 
struct ContainingClassFinder 
{ 
    static_assert(TypeExists<Target_, typename ContainingClasses_::Class...>::value, "No ContainingClass found for Target_."); 
    using ContainingClass = typename std::tuple_element<IndexOf<Target_, typename ContainingClasses_::Class...>::value, 
                 std::tuple<ContainingClasses_...>>::type; 
}; 

using namespace std; 

// Use the meta function to return the id of the ContainingClass that contains a type. 
template <class Target_, class ...ContainingClasses_> 
uint32_t get_containing_id(ContainingClasses_...) 
{ 
    return ContainingClassFinder<Target_, ContainingClasses_...>::ContainingClass::id(); 
} 

struct Foo {}; 
struct Bar {}; 
struct Test {}; 
struct NonExistent {}; 

int main() 
{ 
    // Prove that the right class was found be printing its ID out. 
    // Prints 2. 
    cout << get_containing_id<Test>(ContainingClass<0, Foo>{}, ContainingClass<1, Bar>{}, ContainingClass<2, Test>{}) << endl; 
    // Causes static_assert. 
    //cout << get_containing_id<NonExistent>(ContainingClass<0, Foo>{}, ContainingClass<1, Bar>{}, ContainingClass<2, Test>{}) << endl; 
    return EXIT_SUCCESS; 
} 

これに伴う問題は、それがstd::tupleに依存し、2つの直線を検索していることである:存在チェックのための1つの(第1のヘルパーメタ機能を使用します) 1つはタイプを取得する(std::tuple_elementを使用)。

私は理想的には、2つのヘルパーメタ機能と、std::tupleを必要とせずに、一度にすべてを取得したいと思います。実用的ですか?そうでない場合は、私の実装の改善が認められるでしょう。

注:

1.このメタ関数は、ライブラリの実装の詳細として使用されます。 Boostはオプションではありません。

2.メタ関数の結果は、型でなければなりません。具体的には、対象の型が見つかった型を含む型である必要があります。クラスのid()を取得することは、メタ関数が動作していることを示します。メタ機能により、

3.、私は[更新]これが私のために働いている<type_traits>

+0

再改造の代わりに、おそらくBoost.Hanaをご覧ください。 –

+0

@KerrekSB私に思い出させることに感謝します。私はこれが図書館の一部であると言及することを忘れていました。ブーストは単に選択肢ではありません。 – rationalcoder

+0

私の更新された答えを見てください:コンパイルし、意図したとおりに動作します –

答えて

1

何について次の解決策?

いいえstd::tupleと私が間違っていない場合は、線形検索は1つだけです。

#include <iostream> 
#include <cstdlib> 
#include <type_traits> 

template <uint32_t, class Class_> 
struct ContainingClass 
{ using Class = Class_; }; 

struct Foo {}; 
struct Bar {}; 
struct Test {}; 

template <typename, typename ...> 
struct getContType; 

template <typename T> 
struct getContType<T> 
{ using type = void; }; 

template <typename T, typename CC0, typename ... CCs> 
struct getContType<T, CC0, CCs...> 
{ using type = typename std::conditional<std::is_same<T, 
     typename CC0::Class>::value, CC0, 
     typename getContType<T, CCs...>::type>::type; }; 

int main() 
{ 
    static_assert(std::is_same<ContainingClass<2, Test>, 
       getContType<Test, ContainingClass<0, Foo>, 
       ContainingClass<1, Bar>, ContainingClass<2, Test>>::type 
       >::value, "!"); 

    return EXIT_SUCCESS; 
} 
+0

これは有望に見えるが、IDを取得することはちょうどいいタイプが見つかったことを示すことでした。メタ関数には型の結果が含まれている必要があります。具体的には、対象の型が見つかった型を含む型です。 – rationalcoder

+0

@rationalcoder - よく見る...関数は型のオブジェクトを返すことができます。タイプではありません。私は 'ContainingClass <2, Test>'型のオブジェクトを返すようにソリューションを修正しました。あなたがタイプに興味があるのであれば、関数ではなく型を持つ構造体を作成しなければならないと思います。 – max66

+0

ああ、ここの問題は言葉遣いです。メタ関数では、基本的にtype_traitsで定義されているように、テンプレート化された構造体を参照しています。私はそれを明確にするために私の質問を更新します。私はこの男と同じ意味でそれを意味する:https://www.youtube.com/watch?v = Am2is2QCvxY – rationalcoder

1

で定義されたもののように、テンプレート構造体を参照しています:

// marker for not-found types 
struct none { 
}; 

// fwd declaration 
template <typename Target_,typename ...List_> struct scanner; 

template < 
    typename Target_, 
    typename Head_, typename ...List_ 
> 
struct scanner<Target_, Head_, List_...> { 

    using found_type=typename std::conditional< 
    std::is_same<Target_, Head_>::value, // or any other predicate 
    Head_, 
    // if not, search further 
    typename scanner<Target_, List_...>::found_type 
    >::type; 
    // were are going to reset it anyway if in the end the found_type==none 
    static constexpr int value= 
    std::is_same<Target_, Head_>::value 
    ? 0 
    : scanner<Target_, List_...>::value+1 
    ; 
}; 

// need a recursion stopper for the scanner here. 
template <typename Target_> 
struct scanner<Target_> { 
    using found_type=none; 
    // were are going to reset it anyway if in the end the found_type==none 
    static constexpr int value=-1; 

}; 

template <typename Target, typename... List> 
struct ContainingClassFinder { 
private: 
    using result=scanner<Target, List...>; 
public: 
    static constexpr int value= 
     std::is_same<typename result::found_type, none>::value 
    ? -1 
    : result::value 
    ; 
    using found_type=typename std::enable_if< 
    false==std::is_same<typename result::found_type, none>::value, 
    typename result::found_type 
    >::type; 
}; 

/// brief test 
struct dummy { 

}; 

using good=ContainingClassFinder< 
    int, 
    long, dummy, int, char 
>; 
static_assert(std::is_same<int, good::found_type>::value, "Oops - good type failing"); 
static_assert(good::value==2, "Oops - good index failing"); 


using bad_notfound=ContainingClassFinder< 
    int, 
    long, dummy, float, char 
>; 
static_assert(bad_notfound::value==-1, "Ooops - bad type failing index"); 

// this should create a compilation error due to std::enable_if with a false condition 
using non_existing=typename bad_notfound::found_type; // yeap, it does cause compilation error 
+0

これは、私が失敗した私の元の試みのようです。私はそれをちょっとぶらぶらして、それが私の必要に合っているかどうかを見ます。働く何かにアップグレード更新 – rationalcoder

+0

@rationalcoder /(まだ例として、あなたの目的のための適合性を評価することはできません) –

関連する問題