2016-11-29 40 views
2

有什麼辦法到模板的功能,使其可以接受的一般情況下,T,或以專業化,如果模板參數解析到的東西是可調用的,如函子,函數指針或std::function
例如,我想是這樣的:模板專門爲T和函數對象返回牛逼

template<typename T> 
void use_this(T obj) { 
    obj->do_stuff(); 
} 

template<> 
void use_this<???>(??? func) { 
    use_this(func()); 
} 

use_this(MyObj); // should call first one 
use_this([MyObj](){ return MyObj; }); // should call the second one 

回答

1

不能部分專門函數模板,所以你不能得到你在你的問題表明的語法。

你可以寫兩個函數模板:一個用於當T是可調用不帶任何參數,一個是當它不是。然後,您可以使用expression SFINAE禁用該功能的版本,並添加額外的功能參數進行重載喜歡那個版本時,它可用:

template<typename T> 
void use_this(T obj, float) { 
    obj->do_stuff(); 
} 

template<typename Func> 
auto use_this (Func func, int) -> decltype(func(), void()) { 
    use_this(func()); 
} 

那麼你可以添加它提供本無歧義的說法本身就是一個包裝:

template <typename T> 
void use_this(T&& t) { 
    use_this(std::forward<T>(t), 0); 
} 

Live demo

0
namespace details { 
    template<template<class...>class Z, class, class...Ts> 
    struct can_apply : std::false_type{}; 
    template<template<class...>class Z, class...Ts> 
    struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...> : std::true_type{}; 
} 
template<template<class...>class Z, class...Ts> 
using can_apply = details::can_apply<Z,void, Ts...> 

template<class Sig> 
using can_invoke = can_apply< std::result_of_t, Sig >; 

我們現在有一個特性類can_invoke

你傳給它一個簽名。如果簽名是一個有效的電話,這是真誠的,否則就是錯誤的。

template<class T> 
std::enable_if_t< !can_invoke<T()> > 
use_this(T obj) { 
    obj->do_stuff(); 
} 
template<class T> 
std::enable_if_t< can_invoke<T()> > 
use_this(T func) { 
    use_this(func()); 
} 

我使用一些C++ 11,如enable_if_tvoid_tresult_of_t。所有這些都很容易在C++ 11中編寫,而且很容易搜索。

通過當一個無效簽名被修改在C++ 14的result_of行爲。在C++ 11中,它不一定是SFINAE友好的。我們可以在C++ 11如下與invoke_result_r替換std::result_of_t

template<class Sig, class=void> 
struct invoke_result {}; 
template<class Sig> 
using invoke_result = typename invoke_result<Sig>::type; 

template<class F, class...Args> 
struct invoke_result<F(Args...), 
    decltype(void(std::declval<F>()(std::declval<Args>()...))) 
> { 
    using type = decltype(std::declval<F>()(std::declval<Args>()...)); 
}; 

這是現在SFINAE友好。

can_apply是類似於C++ 20的is_detected,但較短的和對點。

注意,在非C++編譯器11這樣,像MSVC,是不切實際的。但是,您可以使用標籤分派進行類似的操作。