T和返回T的函数对象的模板特化

时间:2016-11-29 15:39:15

标签: c++11 templates

有没有办法模板化一个函数,以便它可以接受通用情况下的T,或者如果模板参数解析为可调用的东西,可以接受专门化,例如仿函数,函数指针或{{1 }}?
例如,我想要这样的东西:

def login(email: String, password: String): Future[Option[User]] = {
    import scala.concurrent.ExecutionContext.Implicits.global

    repo.findBy("email", email)
        .map { userOpt => userOpt.filter(user => BCrypt.checkpw(password, user.password)) }
}

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

x

我们现在有一个特征班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

我使用了一些C ++ 11,例如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() ); } enable_if_tvoid_t。所有这些都很容易用C ++ 11编写,并且易于搜索。

在传递无效签名时result_of_t的行为在C ++ 14中已更改。在C ++ 11中,它不一定是SFINAE友好的。我们可以在C ++ 11中用result_of替换std::result_of_t,如下所示:

invoke_result_r

现在这是SFINAE友好的。

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>()... ) ); }; 类似于C ++ 20的can_apply,但更短,更直观。

请注意,在非C ++ 11编译器(如MSVC)中执行此操作是不切实际的。但是,您可以使用标签分派执行类似的操作。