7

このコードを持つ:

template<class ...Args>
struct Are_Same
{
    enum {value = Are_Same<Args...>::value};
};

template<class A,class... C>
struct Are_Same<A,C...>
{
    enum {value = Are_Same<A,C...>::value};//HERE is THE ERROREOUS LINE
};

template<class A,class B>
struct Are_Same<A,B>
{
    enum {value = std::is_same<A,B>::value};
};  

gcc 4.6.1 からエラーが発生しています:

エラー: ネストされた名前指定子で不完全な型 'Are_Same' が使用されています。

Are_Same<A,C...>::valueそうすることで、最後に単純に展開される再帰呼び出しを呼び出すと思いましたAre_Same<A,B>。明らかにそうではありません。誰が私がどこで間違っているのか知っていますか?

4

3 に答える 3

8

テンプレートの定義が間違っていると思います。どちらの場合も、正確な再帰をトリガーしています。コンパイラーがコンパイラー内のスタックオーバーフローで停止することを期待していましたが、別のエラーが生成されました...

are_same可変個引数テンプレートの実装は次のようになります。

template <class... Args>                    // base (optional to declare the template)
struct are_same;

template <class A, class B, class... Args>  // recursion
struct are_same<A,B,Args...> {
    static const bool value = is_same<A,B>::value && are_same<A,Args...>::value;
};

template <class A, class B>                 // stop condition
struct are_same<A,B> {
    static const bool value = is_same<A,B>::value;
};

このrecursionステップでは、引数のリストから 1 つの引数が削除されていることに注意してください。これにより、解決する新しい問題は元の問題の縮小版になります。このタイプのテンプレート メタプログラミングは再帰と非常に関連しており、同じ規則が適用されます。再帰を使用できるようにするには、各再帰ステップが確実にソリューションに近づくようにする必要があります。この特定のケースでは、N 個の潜在的に同じ型のリストが与えられた場合、各ステップは問題を N-1 個の型が同じかどうかを見つけることに軽減します。

are_same代わりに、問題の縮退バージョンを停止条件として (前のものを置き換えて) 使用できます。

template <class A> 
struct are_same<A> {
   static const bool value = true;
};

これは、単一の型が *are_same* であるかどうかを尋ねるのは実際には意味がないという意味で退化していますが、異なるメタプログラミング タスクに対しては適切である可能性があります。

依存しない別の潜在的により効率的なアルゴリズム (上記の再帰ステップでコンパイラーがテンプレートのインスタンス化を回避するかどうかはわかりません) は次のis_sameようになります。

template <class... Args>
struct are_same;

template <class A, class... Args>
struct are_same<A,A,Args...> {              // recursion
    static const bool value = are_same<A,Args...>::value;
};

template <class A, class B, class... Args>
struct are_same<A,B,Args...> {              // cut, A and B are not the same
    static const bool value = false;
};

template <class A>
struct are_same<A> {                        // end of recursion
    static const bool value = true;
};

この場合、コンパイラは 2 つの型が同じ場合は必ずステップよりも を優先するrecursionため、内部cutでチェックする必要はありません。is_same同時に、コンパイラがcutステップに入った場合、型リストの残りを処理する必要はありません。答えは既にわかっているからです。

于 2011-10-25T08:20:42.917 に答える
3

私はこのようにします:

#include <type_traits>
#include <iostream> 

template <class... Args>
struct are_same
{
  static const bool value=true;
};

template <class A, class B, class... Args>  // recursion
struct are_same<A,B,Args...> {
    static const bool value = std::is_same<A,B>::value && are_same<B,Args...>::value;
};

int main()
{
    std::cout<< std::boolalpha << are_same< int >::value << std::endl;
    std::cout<< std::boolalpha << are_same< int, int, int >::value << std::endl;
    std::cout<< std::boolalpha << are_same< int, int, double, int >::value << std::endl;
}
于 2011-10-25T08:32:50.103 に答える
0

おそらく最も単純な実装は次のようになります。

template <typename... TList>
struct are_same { constexpr static bool value = false; };

template <typename T, typename... TList>
struct are_same<T, T, TList...> { 
    constexpr static bool value = are_same<T, TList...>::value; 
};

template <typename T>
struct are_same<T> { constexpr static bool value = true; };

または、停止条件を次のように置き換えることができます

template <typename T>
struct are_same<T, T> { constexpr static bool value = true; };

しかし、最初のものはより一般的ですare_same<type>::value == true。別の問題は、何とare_same<>::value等しいかということです。これで得られますfalseが、このようなテンプレートの特殊化をもう 1 つ追加することは大したことではありません。

template <>
struct are_same<> { constexpr static bool value = true; };
于 2013-07-31T08:20:07.460 に答える