2016-10-12 13 views
22

私はHow to implement a constant-expression counter in C++チュートリアルに従っています。そして、私はC++14 Reflections Without Macros, Markup nor External Tooling..話の制限を修正しようとしています。C++ ADLを使ってテンプレートのすべてのインスタンスを調べる方法は?

チュートリアルの基本的な考え方はこれです:

template<int N> 
struct flag { 
    friend constexpr int adl_flag (flag<N>); 
}; 

template<int N> 
struct writer { 
    friend constexpr int adl_flag (flag<N>) { return N; } 
    static constexpr int value = N; 
}; 

template<int N, class = char[noexcept(adl_flag(flag<N>()))?+1:-1]> 
int constexpr reader (int, flag<N>) { return N; } 

template<int N> 
int constexpr reader (float, flag<N>, int R = reader (0, flag<N-1>())) { return R; } 

int constexpr reader (float, flag<0>) { return 0; } 

template<int N = 1, int C = reader (0, flag<32>())> 
int constexpr next (int R = writer<C + N>::value) { return R; } 

int main() { 
    constexpr int a = next(); 
    constexpr int b = next(); 
    constexpr int c = next(); 

    // YES! it works!!! 
    static_assert (a == 1 && b == a+1 && c == b+1, "try again"); 
} 

注:あなたが今では興味を持っていない場合、それは

:-)読み取りを停止する良い時間だと話がどのように説明して集約初期化と暗黙の変換演算子を使用してPODタイプのフィールド数とフィールドタイプを抽出しますが、主な制限はプリミティブ型のみがサポートされていることです。

私は上記の背景を私の動機を正当化するために提供しました!

私はこれに来たこれらの2つのアプローチを組み合わせ:

template<int N> 
struct flag { 
    friend constexpr int adl_flag (flag<N>); 
}; 

template<typename T, int N> 
struct writer { 
    friend constexpr int adl_flag (flag<N>) { 
    return N; 
    } 
    friend constexpr T field_type(flag<N>) { return T{}; } 
    static constexpr int value = N; 
}; 

field_type(flag<N>)は私にN番目のフィールドの型を与えるだろうし。 これは友人の関数であり、番目のフィールドのPODタイプのちょうど1つは、field_type(flag<N>)がコンパイラによって定義されることに注意してください。

g++decltype(field_type(flag<1>))についてはno matching function for call to 'field_type(flag<1>)となります。

ADLをどうにかして、writer<T,N>のすべてのインスタンスを検索する必要があります。 どうすればいいですか?

更新@ T.C.mentioned ADLのみ関連するクラスに見えるよう

、およびwriterは1ではありません。

全体の問題は、どのようにADLはそれを見つけることができるようにT値を知らなくてもwriter関連するクラスを作ることです - (ADLはそれを見つけることができるようにadl_flagflagで宣言されている理由ですか。)?

+1

委員会がカウンタの全体を禁止することを考慮すると、私はspこれで終了時間。 –

+0

いずれにしても、ADL(これはODRとは関係ありません)は関連するクラスのみを調べ、 'writer'は1つではありません。 (そのため、 'adl_flag'は' flag'に宣言され、ADLはそれを見つけることができます。) –

+2

@ T.C。 「委員会はカウンターのことを禁止しようとしている」その意図を示す参考資料を教えてもらえますか?メタカウンタの使用が古いというADLルールは古いものです。おそらく数百万のコードラインを壊すことなく、どのように委員会がルールを変更しようとしているのですか? – amin

答えて

2

は、GCC 4.9で

のみ動作します(C++ 14の後にのみ利用可能)戻り値の型autoで、フラグテンプレートにfield_type宣言を追加します。代わりにnoexceptの自動機能の

#include <type_traits> 

template<int N> 
struct flag { 
    friend constexpr int adl_flag (flag<N>); 
    friend constexpr auto field_type(flag<N>); 
}; 

template<typename T, int N> 
struct writer { 
    friend constexpr int adl_flag (flag<N>) { return N; } 
    friend constexpr auto field_type(flag<N>) { return (T&&)(*(T*)0); } // remove default constructable restriction 
    static constexpr int value = N; 
}; 

template<int N, class = char[noexcept(adl_flag(flag<N>()))?+1:-1]> 
int constexpr reader (int, flag<N>) { return N; } 

template<int N> 
int constexpr reader (float, flag<N>, int R = reader (0, flag<N-1>())) { return R; } 

int constexpr reader (float, flag<0>) { return 0; } 

template<typename T, int N = 1, int C = reader (0, flag<32>())> 
int constexpr next (int R = writer<T, C + N>::value) { return R; } 

int main() { 
    constexpr int a = next<int>(); 
    constexpr int b = next<double>(); 
    constexpr int c = next<long>(); 

    // YES! it works!!! 
    static_assert (a == 1 && b == a+1 && c == b+1, "try again"); 
    static_assert(std::is_same<decltype(field_type(flag<1>{})), int>{}, "first is int"); 
    static_assert(std::is_same<decltype(field_type(flag<2>{})), double>{}, "second is double"); 
    static_assert(std::is_same<decltype(field_type(flag<3>{})), long>{}, "third is long"); 

} 

使用decltypeを、 gcc 5.2、clang 3.5.1 - 3.7.1の後で動作します:

#include <type_traits> 

template <int N> 
struct flag { 
    constexpr friend auto adl_flag(flag<N>); 
    friend auto field_type(flag<N>); 
}; 

template<typename T, int N> 
struct writer { 
    friend constexpr auto adl_flag(flag<N>) { return 0; } 
    friend auto field_type(flag<N>) { return (T&&)(*(T*)0); } 
    static constexpr int value = N; 
}; 

template<int N, class = decltype(adl_flag(flag<N>{}))> 
int constexpr reader (int, flag<N>) { return N; } 

template<int N> 
int constexpr reader (float, flag<N>, int R = reader (0, flag<N-1>())) { return R; } 

int constexpr reader (float, flag<0>) { return 0; } 

template<typename T, int N = 1, int C = reader (0, flag<32>())> 
int constexpr next (int R = writer<T, C + N>::value) { return R; } 

int main() { 
    constexpr int a = next<int>(); 
    constexpr int b = next<double>(); 
    constexpr int c = next<long>(); 

    // YES! it works!!! 
    static_assert (a == 1 && b == a+1 && c == b+1, "try again"); 
    static_assert(std::is_same<decltype(field_type(flag<1>{})), int>{}, "first is int"); 
    static_assert(std::is_same<decltype(field_type(flag<2>{})), double>{}, "second is double"); 
    static_assert(std::is_same<decltype(field_type(flag<3>{})), long>{}, "third is long"); 

} 
関連する問題