如何在不知道其返回类型的情况下检查类是否具有模板化的invoke操作符?

时间:2018-12-13 19:54:55

标签: c++ c++14 template-meta-programming typetraits

我有一个模板函数

template <typename F, typename T> auto foo(F f) { ... }

在此函数内,我想调用F:我想调用 F.template operator()<T>(),不带参数-但仅当它存在时。否则,我将返回一些my_type_t类型的值。

我已经阅读了这个问题:

Check if a class has a member function of a given signature

及更高版本:

Using `void_t` to check if a class has a method with a specific signature

及其答案。但是,他们似乎都假设您事先知道签名,因此可以使用std::is_same确保该方法确实存在并产生相关类型。

就我而言-我不知道要针对哪种类型进行检查。

那我该怎么做,这没有做任何假设?

1 个答案:

答案 0 :(得分:-1)

正如评论员所建议的(感谢@DanHulme),这在SFINAE上无需任何假设即可完成-类似于

Find out whether a C++ object is callable

至少在一定的假设下。

但是,由于C ++语法的含糊性,对于模板化的operator()正确获取代码有些棘手。我还添加了一些评论,以简要地解释SFINAE在这里的工作方式,以支持那些对C ++不太了解的读者(对于代码,而不是对这个问题的理解)。

无论如何,这是改编:

#include <type_traits>

namespace detail {    

template <class>
struct sfinae_true : std::true_type{};

template <class F, typename T>
static auto test_invoke_operator(int ) ->
    sfinae_true<decltype(std::declval<F>().template operator()<T>())>;

template <class, typename>
static auto test_invoke_operator(long) -> std::false_type;

} // namespace detail

template <class F, typename T>
struct has_invoke_operator : decltype( detail::test_invoke_operator<F,T>(int{}) )
{ };
    // The overload resolution here will depend on the test for invoke_operator:
    // * If F has an operator()<T>, the `int` variant substitution succeeds,
    //   so has_invoke_operator inherits true_type.
    // * If F does not have an operator()<T>, the `int` variant substitution fails,
    //   but we still get a matching candidate - the `long` variant, which
    //   means has_invoke_operator inherits false_type

Working example on Coliru

在Coliru示例中-我们需要用= delete来表明该类 没有任何其他专门的定义,也没有广义的定义。