3

Foo私はクラスを持っています。いくつかのメソッドでそれを呼び出しましょう:

template<typename T>
class Foo {
public:
   Foo()               { /* ... */ }
   bool do_something() { /* ... */ }

   // This method should be callable only if:
   // std::is_floating_point<T>::value == true
   void bar() { 
      // Do stuff that is impossible with integer
   }
};

と の両方を構築できるようにしたいのですが、型 T が浮動小数点型でない場合の呼び出しを許可したくありませんFoo<double>。また、実行時ではなくコンパイル時にエラーが生成されるようにします。だから、私が欲しいのは:Foo<int>bar()

Foo<double> a;
a.bar();                        // OK
Foo<int> b;
bool res = b.do_something();    // OK
b.bar();                        // WRONG: compile error

( thisまたはthis oneenable_ifのような投稿で)で多くのことを試しましたが、 でタイプを使用できなくなりました。例えば:intFoo

typename std::enable_if<std::is_floating_point<T>::value>::type
bar() { /* ... */ } 

main.cpp:112:28:   required from here
foo.h:336:5: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
 bar() {

bar()浮動小数点型の使用を制限し、整数型を他の場所で使用できるようにするにはどうすればよいですか?

4

2 に答える 2

3

基本的な解決策はstatic_assert、 の本体内で a を使用することですbar。誰かがそれを呼び出そうとした場合にのみ、これはエラーを生成します。ただし、人々がそれを見つけるのをブロックするわけではなく、SFINAE によるbar.

の代わりにstatic_assert、SFINAE を使用して、条件付きbarでオーバーロード解決への参加を許可し、場合によっては、オーバーロードの解決がまったく検出されないようにブロックすることができます。SFINAE は理論的にはコンパイル可能な特殊化を持っている必要があり (そうでない場合、プログラムの形式が正しくなく、診断は必要ありません)、メソッドでのみ機能するため、注意が必要ですtemplate

private:
  struct blocked {};
public:
  template<typename Unused=void, 
           typename=typename std::enable_if< 
                                     std::is_same<Unused, blocked>::value ||                            
                                     std::is_floating_point<T>::value 
                                           >::type>
  void bar() {
    // code
  }

これにより、メソッドのbar選択がエラーになるのではなく、オーバーロードの解決中にメソッドが考慮されなくなります。これは微妙な違いですが、barオーバーライドされた場合は非常に重要になります。

これはかなり鈍いです。C++1y のコンセプト ライトでは、句は上記の鈍いものなしrequiresで a 内で正しいことを行うことになっています。template

実際には、有効な特殊化を持たないblockeda の不正な形式を実際に強制するコンパイラを認識していないため、型はおそらく必要ありません。templateその節はおそらく、将来のリビジョンがインスタンス化の前により多くのチェックを行えるようにするために存在します。

私が考えることができる最後の方法には、作成/破棄する特性に基づいて特殊化する CRTP 基本クラスが含まbarれます。

template<typename D, bool test>
struct maybe_bar {};
template<typename D>
struct maybe_bar<D, true> {
  D* self() {
    static_assert( std::is_base_of< maybe_bar, D >::value, "CRTP failure" );
    return static_cast<D*>(this);
  }
  D const* self() const{
    static_assert( std::is_base_of< maybe_bar, D >::value, "CRTP failure" );
    return static_cast<D const*>(this);
  }
  void bar() {
    // use self() in here to get at your this pointer instead of this
  }
};

次に、使用時に:

template<typename T>
struct my_type:maybe_bar<T, std::is_floating_point<T>::value> {
};

bar条件付きで作成されるかどうか。

これはそれほど鈍感ではありませんが、より冗長であり、実装をクラス本体の残りの部分から大きく逸脱させています。

于 2014-05-09T20:23:22.480 に答える