1

私はこのコードを持っていますが、コンパイルしません:

#include <iostream>
#include <stdexcept>
#include <cassert>


template< class > struct id{};
template< class U, class V> struct base: public id<U>, public id<V>
{
    static const bool value = true;
};

template< class U, class V>
struct is_different
{

  typedef char (&true_)[1];
  typedef char (&false_)[2];

  template< class T, class K, bool  = base<T,K>::value >
  struct checker;



  template< class T, class K>
  static true_  test( checker<T,K>* );

  template< class , class >
  static false_  test(...);


  static const bool value = sizeof( test<U,V>(0) ) == sizeof(true_);

};


int main (void) 
{
    bool b1 = is_different<int,float>::value;
    bool b2 = is_different<int,int>::value; // <--- error

    std::cout << std::boolalpha << b1 << '\n'
                                << b2  << '\n';
    return 0;       
}

エラー:

main.cpp: In instantiation of ‘struct base<int, int>’:
main.cpp:25:17:   required by substitution of ‘template<class T, class K> static char (& is_different<U, V>::test(is_different<U, V>::checker<T, K>*))[1] [with T = T; K = K; U = int; V = int] [with T = int; K = int]’
main.cpp:31:41:   required from ‘const bool is_different<int, int>::value’
main.cpp:39:38:   required from here
main.cpp:7:36: error: duplicate base type ‘id<int>’ invalid
 template< class U, class V> struct base: public id<U>, public id<V>

重複継承の失敗を SFINAE として使用できないのはなぜですか?

4

1 に答える 1

2

SFINAE は、関数シグネチャ内で直接適用されるものにのみ適用されます。取得するコンパイル エラーはbase<T, K>、関数シグネチャから 2 つのステップを削除した のインスタンス化内で発生します。

そうは言っても、なぜこれを難しい方法で行うのですか?

template <typename T, typename U>
struct is_same { static const bool value = false; };

template <typename T>
struct is_same<T, T> { static const bool value = true; };

template <typename T, typename U>
struct is_different { static const bool value = !is_same<T, U>::value; };

編集:

コメントでの質問に答えるために、SFINAE についてもう少し説明させてください。標準では、17.8.2p8 で SFINAE が指定されています。

置換の結果が無効な型または再表現になる場合、型推定は失敗します。無効な型または再表現は、置換された引数を使用して記述された場合に不適切な形式になるものです。関数の型とそのテンプレート パラメーターの型の直接のコンテキストで無効な型と式のみが推定エラーになる可能性があります。[注:置換された型と式の評価は、クラス テンプレートの特殊化および/または関数テンプレートの特殊化のインスタンス化、暗黙的に定義された関数の生成などの副作用をもたらす可能性があります。このような副作用は「即時のコンテキスト」にはなく、プログラムの形式が正しくない可能性があります。-終了注記

ここで問題になるのは、「即時コンテキスト」です。ここでは、直接のコンテキストからエラーを削除する 2 つのことを行っています。

  • のデフォルトの引数式の評価中にエラーが発生しますchecker。この評価は、オーバーロードの解決のためにインスタンス化さchecker<T,K>れる の引数リストでのの発生によってトリガーされtestますが、直接のコンテキストではありません。baseの定義をに変更することで、これを試すことができますtemplate <typename T, typename U> struct base {};。これにより、basego のインスタンス化のエラーが解消され、デフォルトの引数式のコンテキストでのエラーに置き換えられます ("does not have a member called value")。ただし、SFINAE はまだトリガーされません。それでもハードエラーが発生します。
  • の定義のインスタンス化でエラーが発生しましたbase。これは、オーバーロードの解決から削除されたもう 1 つのステップです。同じ理由で、メンバーをbasewith 型に入れても、 type が含まれT::foobarているかどうかを調べることはできません: の定義はもはや SFINAE コンテキストではありません。画像から削除すると、これだけでもエラーであることがわかります。たとえば、次のようにします。Tfoobarbasechecker

 

template <typename U, typename V> struct base: public id<U>, public id<V> {
    typedef void type;
};
template <typename U, typename V> struct is_different {
  struct true_ { char c[1]; };  // I don't like sizeof(reference type),
  struct false_ { char c[2]; }; // makes me nervous.
  template <typename T, typename K>
  static true_ test(typename base<T, K>::type*);
  template <typename, typename>
  static false_ test(...);

  static const bool value = sizeof(test<U, V>(0)) == sizeof(true_);
};

インスタンス化は、テンプレートのデフォルトの引数式の背後に隠れることはありませんが、署名の中にありますbaseが、それでもエラーが発生します。

于 2013-10-22T11:33:11.847 に答える