2017-10-18 47 views
3

我試圖理解爲什麼這片代碼工作不正常C++ enable_if_t SFINAE

#include <cstdio> 
#include <vector> 
#include <type_traits> 
using namespace std; 

struct Foo { 

}; 

template<typename T, typename = void> 
void compare(const T&a, const T&b) { 
    cout << "default" << endl; 
} 

template<typename T, std::enable_if_t<std::is_same<T, Foo>::value>> 
void compare(const T& a, const T &b) { 
    cout << "In object" << endl; 
} 

int main(int argc, char const *argv[]) { 
    compare(1, 2); 

    { 
     vector<int> a, b; 
     compare(a, b); 
    } 

    { 
     Foo a, b; 
     compare(a, b); 
    } 

    return 0; 
} 

在所有情況下的「默認」被打印出來。對於最後一種情況,我期望第二個函數被調用。

回答

3

你沒有專注於compare(無論如何都不可能部分專門化一個函數模板)。相反,你提供了一個重載。

而且超載總是非法的:

  1. 要麼enable_if_t沒有定義。
  2. 或者它指定void類型的非類型模板參數。

所以它永遠不會被調用,因爲SFINAE會放棄它,轉而支持頂部始終有效的過載。

專業化通常是功能模板的錯誤答案。相反,你應該委託給一個類模板,它表現在真正的專業化預期:

template<typename T, typename = void> 
struct compare_impl { 
    static void execute(T const& l, T const& r) { /*Base case code*/ } 
}; 

template<typename T> 
struct compare_impl<T, std::enable_if_t<std::is_same<T, Foo>::value>> { 
    static void execute(T const& l, T const& r) { /*Special case code*/ } 
}; 

template<typename T> 
void compare (T const& l, T const& r) { compare_impl<T>::execute(a, b); } 
+0

謝謝!我現在理解:)在比較功能,我們需要做compare_impl ::相反,我想 –

+0

@jack_carver - 確認,我知道我會錯過的東西。 – StoryTeller

+0

您也可以在'compare'函數中從參數'(l,r)'切換到'(a,b)'。 –

1

推遲到專門的函數對象允許很大的靈活性如何參數類型和/或他們是否是右值或左值。

#include <iostream> 
#include <vector> 
#include <type_traits> 
using namespace std; 


// general case 
template<class T> 
struct compare_impl 
{ 
    template<class U, class V> 
    auto operator()(U&& a, V&& b) const { 
     cout << "default" << endl; 
    } 
}; 

// compare interface 
template<class T, class U> 
auto compare(T && a, U && b) 
{ 
    using ctype = std::common_type_t<std::decay_t<T>, std::decay_t<U>>; 
    auto impl = compare_impl<ctype>(); 
    return impl(a, b); 
} 


// now specialise for objects for which we want custom behaviour 
struct Foo { 

}; 

template<> 
struct compare_impl<Foo> 
{ 
    template<class U, class V> 
    auto operator()(U&& a, V&& b) const { 
     cout << "In object" << endl; 
    } 
}; 


int main(int argc, char const *argv[]) { 

    compare(1, 2); 

    { 
     vector<int> a, b; 
     compare(a, b); 
    } 

    { 
     Foo a, b; 
     compare(a, b); 
    } 

    return 0; 
} 
2

使用類模板是一個有效的解決方案,這裏的另一種方式與標籤的調度,以實現這一結果:

template <class T> 
    void compare(const T & l, const T & r, std::true_type) 
    { 
     cout << "In object" << endl; 
    } 

    template <class T> 
    void compare(const T & l, const T & r, std::false_type) 
    { 
     cout << "default" << endl; 
    } 

    template <class T> 
    void compare(const T & l, const T & r) 
    { 
     compare(l, r, std::is_same<T, Foo>{}); 
    }