2016-11-10 12 views
5

cppreference.com(http://en.cppreference.com/w/cpp/types/enable_if#Notes)指出:使用模板,如何區分兩個並行的情況,例如浮點類型和整型之間的區別?

一個常見的錯誤是隻聲明在其默認模板參數的不同的兩個函數模板。這是非法的,因爲默認模板參數不是函數模板簽名的一部分,並且聲明具有相同簽名的兩個不同函數模板是非法的。

struct T { 
    enum { int_t,float_t } m_type; 
    template <typename Integer, 
       typename = std::enable_if_t<std::is_integral<Integer>::value> 
    > 
    T(Integer) : m_type(int_t) {} 

    template <typename Floating, 
       typename = std::enable_if_t<std::is_floating_point<Floating>::value> 
    > 
    T(Floating) : m_type(float_t) {} // error: cannot overload 
}; 

所以真的...那麼,什麼是解決這個問題,真正實現上面有哪些不正確的代碼無法實現正確的做法?

回答

5

我相信這會工作:

#include <type_traits> 

struct T { 
    enum { int_t,float_t } m_type; 
    template <typename Integer, 
       std::enable_if_t<std::is_integral<Integer>::value>* = nullptr 
    > 
    T(Integer) : m_type(int_t) {} 

    template <typename Floating, 
       std::enable_if_t<std::is_floating_point<Floating>::value>* = nullptr 
    > 
    T(Floating) : m_type(float_t) {} // now the overload is valid 
}; 

int main() { 
    T t = int{}; 
    T t2 = float{}; 
    (void)t; 
    (void)t2; 
} 

[live demo]

1

使用enable_if在構造函數的參數列表中的另一僞參數:

struct T { 
    enum { int_t,float_t } m_type; 

    template <typename Integer> 
    T(Integer, std::enable_if_t<std::is_integral<Integer>::value>* = nullptr) 
     : m_type(int_t) {} 

    template <typename Floating> 
    T(Floating, std::enable_if_t<std::is_floating_point<Floating>::value>* = nullptr) 
     : m_type(float_t) {} 
}; 
4

使用標籤調度:

namespace tag 
{ 
struct floating{}; 
struct integer{}; 
struct error{}; 

template<typename T, typename = void> struct get : error {}; 

template<typename T> 
struct get<T, std::enable_if_t<std::is_integral<T>::value>> : integer {}; 

template<typename T> 
struct get<T, std::enable_if_t<std::is_floating_point<T>::value>> : floating {}; 

} 

struct Foo 
{ 
    template<typename T> 
    Foo(T&&, tag::floating){ 
    } 

    template<typename T> 
    Foo(T&&, tag::integer){ 
    } 

    template<typename T> 
    Foo(T&& t) : Foo(std::forward<T>(t), tag::get<std::decay_t<T>>{}) {} 
}; 

demo

+0

這似乎很尷尬,如果每次調用某個方法時,都必須手動傳遞一個標籤,告訴C++「float」是一個浮點類型,而「int」是一個整型...不是更好嗎讓C++自己來分析它? – gaazkam

+0

@gaazkam嗯,這是一個建立在C++中的非常靈活的習慣用法(只需查看'iterator_traits')。例如,如果您將標記構建爲層次結構(可以爲「random_iterator_tag」和「bidirectional_iterator_tag」提供重載),則可以使用重載解析機制來選擇想要的重載,並選擇回退到更通用的重載。 )。如果你想支持另一組類型,那麼擴展這種方法比使用ifs的嵌套容易得多。 – krzaq

0

我相信我找到了另一種解決方法。這可悲的是不會因使用範圍內浮動模板點類型的侷限性彩車工作,但應對大多數其他情況下仍然工作(如符號和無符號類型之間的區別):

struct T { 
    enum { signed_t,unsigned_t } m_type; 
    template <typename Signed, 
       std::enable_if_t<std::is_signed<Signed>::value, bool> = true 
    > 
    T(Signed) : m_type(signed_t) {} 

    template <typename Unsigned, 
       std::enable_if_t<std::is_unsigned<Unsigned>::value, bool> = true 
    > 
    T(Unsigned) : m_type(unsigned_t) {} 
}; 

活生生的例子:http://ideone.com/xqp4nd

+1

您不必爲'std :: enable_if_t'使用不同的返回類型。 – Jarod42

+0

@ Jarod42 Err,否則我會在我的問題中提到的問題,不是嗎? – gaazkam

+1

沒有,即使你刪除默認情況下,你仍然有不同的類型:'的std :: enable_if_t <性病:: is_signed ::值>''VS的std :: enable_if_t <性病:: is_unsigned ::值>'。 – Jarod42

相關問題