2012-12-09 83 views
20

這裏就是我想要做的事:檢查是否存在成員使用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這個問題,或者如果它甚至可以應用。

+1

'enable_if'不用於檢查成員是否存在,而是用於刪除重載。 – Pubby

+0

我不能用它來做類似的事情(上面編輯中的建議)嗎? – bobobobo

+0

不,你想要一個不存在的'static if'。你想要的是完全可能的,它不會使用那樣的語法。 – Pubby

回答

23

這已經變得方式更容易與C + + 11。

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 
    } 
}; 

注意事項:

  • 可以命名在decltypesizeof非靜態數據成員,而無需一個對象。
  • 您可以申請延長的SFINAE。基本上可以檢查任何表達式,如果在替換參數時無效,模板將被忽略。
+0

這肯定比[之前](http://stackoverflow.com/a/6324863/111307)更好的SFINAE,您必須爲每個想要檢測的成員類型創建一個成員檢測器。但爲什麼人們總是跳到SFINAE,我更喜歡使用[type traits](http://stackoverflow.com/questions/13787490/how-do-you-use-type-traits-to-do-conditional-compilation)現在就做這種類型的條件編譯。 – bobobobo

+0

我想這取決於你是否有更多類型的檢查或更多的成員檢查? –

+1

只有在事先知道類型的情況下,類型特徵纔會有所幫助。在你的鏈接中,你必須知道VertexN是特殊的類。所以他們可能會在OP的例子中工作,但即使你不知道其他類型將會怎樣,SFINAE也能工作,哪個IMO更好的封裝。 –

6

您需要一個元函數來檢測您的成員,以便您可以使用enable_if。這樣做的成語叫做Member Detector。這有點棘手,但它可以做到!

1

這不是您的確切案例的答案,但它是一般問題標題和問題的替代答案。

#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

致信frenode IRC上的dyreshark#C++