web-dev-qa-db-ja.com

enable_ifを使用してメンバーが存在するかどうかを確認します

これが私がやろうとしていることです:

template <typename T> struct Model
{
    vector<T> vertices ;

    #if T has a .normal member
    void transform( Matrix m )
    {
        each vertex in vertices
        {
          vertex.pos = m * vertex.pos ;
          vertex.normal = m * vertex.normal ;
        }
    }
    #endif

    #if T has NO .normal member
    void transform( Matrix m )
    {
        each vertex in vertices
        {
          vertex.pos = m * vertex.pos ;
        }
    }
    #endif
} ;

私は examples を使用してenable_ifを使用しているのを見ましたが、enable_ifをこの問題に適用する方法、またはそれを適用できるかどうか理解できません。

30
bobobobo

これはC++ 11でwayより簡単になりました。

template <typename T> struct Model
{
    vector<T> vertices;

    void transform( Matrix m )
    {
        for(auto &&vertex : vertices)
        {
          vertex.pos = m * vertex.pos;
          modifyNormal(vertex, m, special_());
        }
    }

private:

    struct general_ {};
    struct special_ : general_ {};
    template<typename> struct int_ { typedef int type; };

    template<typename Lhs, typename Rhs,
             typename int_<decltype(Lhs::normal)>::type = 0>
    void modifyNormal(Lhs &&lhs, Rhs &&rhs, special_) {
       lhs.normal = rhs * lhs.normal;
    }

    template<typename Lhs, typename Rhs>
    void modifyNormal(Lhs &&lhs, Rhs &&rhs, general_) {
       // do nothing
    }
};

注意事項:

  • オブジェクトを必要とせずに、decltypeおよびsizeofの非静的データメンバーに名前を付けることができます。
  • 拡張SFINAEを適用できます。基本的に任意の式をチェックでき、引数が置換されたときに有効でない場合、テンプレートは無視されます。

enable_ifを使用するには、メンバーを検出するためのメタ関数が必要です。これを行うイディオムは Member Detector と呼ばれます。少しトリッキーですが、それは可能です!

7
ltjax

これは正確なケースへの回答ではありませんが、質問のタイトルと一般的な問題に対する代替の回答です。

#include <iostream>
#include <vector>

struct Foo {
    size_t length() { return 5; }
};

struct Bar {
    void length();
};

template <typename R, bool result = std::is_same<decltype(((R*)nullptr)->length()), size_t>::value>
constexpr bool hasLengthHelper(int) { 
    return result;
}

template <typename R>
constexpr bool hasLengthHelper(...) { return false; }

template <typename R>
constexpr bool hasLength() {
    return hasLengthHelper<R>(0);
}

// function is only valid if `.length()` is present, with return type `size_t`
template <typename R>
typename std::enable_if<hasLength<R>(), size_t>::type lengthOf (R r) {
  return r.length();
}

int main() {
    std::cout << 
      hasLength<Foo>() << "; " <<
      hasLength<std::vector<int>>() << "; " <<
      hasLength<Bar>() << ";" <<
      lengthOf(Foo()) <<
      std::endl;
    // 1; 0; 0; 5

    return 0;
}

関連 https://ideone.com/utZqjk

freenodeのdyresharkへのクレジットIRC #c ++

2
template<
typename HTYPE, 
typename = std::enable_if_t<std::is_same<decltype(HTYPE::var1), decltype(HTYPE::var1)>::value>
>
static void close_release
(HTYPE* ptr) {
    ptr->var1;
}

Enable_ifとdecltypeを使用してコンパイラーが変数をチェックできるようにします。

0
vrqq