2016-11-29 71 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,是不切实际的。但是,您可以使用标签分派进行类似的操作。