2017-06-19 69 views
2

在一個類中,我有兩種不同的方法,根據調用者模板參數應該是相互排斥的。C++ 03:相互排斥的方法,由於enable_if

class Foo 
{ 
    // For collections 
    template<class T> 
    typename boost::enable_if<boost::is_same<typename std::vector<typename T::value_type>, T>::value, const T&>::type 
    doSomething() 
    { } 


    // For single types 
    template<class T> 
    typename boost::enable_if<!boost::is_same<typename std::vector<typename T::value_type>, T>::value, const T&>::type 
    doSomething() 
    { } 
} 

這不會編譯。

error: type/value mismatch at argument 1 in template parameter list for 'template struct boost::enable_if' error: expected a type, got '! boost::is_same::value'

+2

也許你想'boost :: enable_if_c'?見例如[Boost enable_if參考](http://www.boost.org/doc/libs/1_64_0/libs/core/doc/html/core/enable_if.html)。 –

+0

爲什麼不能使用'disable_if' – danielspaniol

+2

奇怪,爲什麼在'doSomething()'之前指定'const T&',因爲返回類型應該已經由'typename boost :: enable_if ...'指定了? – Alexey

回答

-1

如果你想要的是超載基礎上的功能是否給你一個載體或不

#include <type_traits> 
#include <iostream> 
#include <vector> 

using std::cout; 
using std::endl; 

class Foo { 
public: 
    // For collections 
    template <class T> 
    const vector<T>& do_something(const std::vector<T>& input) { 
     cout << __PRETTY_FUNCTION__ << endl; 
     return input; 
    } 


    // For single types 
    template <class T> 
    const T& do_something(const T& input) { 
     cout << __PRETTY_FUNCTION__ << endl; 
     return input; 
    } 
}; 

int main() { 
    auto foo = Foo{}; 
    auto v = std::vector<int>{}; 
    auto i = int{}; 
    foo.do_something(v); 
    foo.do_something(i); 
} 

如果你想更加普遍和檢查任何實例化的類型

#include <type_traits> 
#include <iostream> 
#include <vector> 

using std::cout; 
using std::endl; 

namespace { 

    template <typename T, template <typename...> class TT> 
    struct IsInstantiationOf 
      : public std::integral_constant<bool, false> {}; 
    template <template <typename...> class TT, typename... Args> 
    struct IsInstantiationOf<TT<Args...>, TT> 
      : public std::integral_constant<bool, true> {}; 
} // namespace anonymous 

class Foo { 
public: 
    // For collections 
    template <typename VectorType, typename std::enable_if_t<IsInstantiationOf< 
      std::decay_t<VectorType>, std::vector>::value>* = nullptr> 
    void do_something(VectorType&&) { 
     cout << "Vector overload" << endl; 
    } 

    // For single types 
    template <class T, typename std::enable_if_t<!IsInstantiationOf< 
      std::decay_t<T>, std::vector>::value>* = nullptr> 
    void do_something(T&&) { 
     cout << "Non vector overload" << endl; 
    } 
}; 

int main() { 
    auto foo = Foo{}; 
    auto v = std::vector<int>{}; 
    auto i = int{}; 
    foo.do_something(v); 
    foo.do_something(i); 
} 

另請注意,您應該避免將std::enable_if放在函數簽名中,可能由於這些原因https://stackoverflow.com/a/14623831/5501675

+0

函數的返回類型是模板類型T,我無法用簡單的函數重載進行排序,我需要SFINAE – codeJack

+0

@codeJack再次編輯使用SFINAE,如果這是你想要的 – Curious

+0

@downvoter爲什麼downvote? – Curious

1

如何:

template <typename T> struct is_std_vector : std::false_type {}; 
template <typename T, typename A> 
struct is_std_vector<std::vector<T, A>> : std::true_type {}; 

然後

class Foo 
{ 
    // For collections 
    template<class T> 
    typename std::enable_if<is_std_vector<T>::value, const T&>::type 
    doSomething(); 

    // For single types 
    template<class T> 
    typename std::enable_if<!is_std_vector<T>::value, const T&>::type 
    doSomething(); 
}; 
+0

這種有效。但爲什麼我不能使用自己的語法而不需要定義is_std_vector結構? – codeJack

+1

'T :: value_type'沒有爲所有類型定義,所以你SFINAE也是這樣,它對於大多數非容器類型都是不正確的。 – Jarod42

0

不像std的版本,boost::enable_if接受型(下布爾值還挺包裝器),所以你應該喜歡寫東西

class Foo 
{ 
    // For collections 
    template<class T> 
    typename boost::enable_if< 
     typename boost::is_same<typename std::vector<typename T::value_type>, T>, 
    const T&>::type doSomething() 
    { } 


    // For single types 
    template<class T> 
    typename boost::enable_if_с< 
     !boost::is_same<typename std::vector<typename T::value_type>, T>::value, 
    const T&>::type doSomething() 
    { } 
} 

請注意這裏,我已經使用typename之前boost::is_same,並沒有在第一個規範中使用::value。相反,我不得不在第二次過載中使用enable_if_с,因爲!運算符不適用於某個類型。

0

怎麼樣的一種標籤調度?

#include <vector> 
#include <iostream> 

template <typename, typename> 
struct isSame 
{ typedef int type; }; 

template <typename T> 
struct isSame<T, T> 
{ typedef long type; }; 

struct foo 
{ 
    template <typename T> 
    T const & doSomething (T const & t, int) 
    { std::cout << "int version" << std::endl; return t; } 

    template <typename T> 
    T const & doSomething (T const & t, long) 
    { std::cout << "long version" << std::endl; return t; } 

    template <typename T> 
    T const & doSomething (T const & t) 
    { return doSomething(t, typename isSame< 
     typename std::vector<typename T::value_type>, T>::type()); } 
}; 

int main() 
{ 
    foo f; 
    std::vector<int> v; 
    f.doSomething(v); // print "long version" 
}