如何使用sfinae来检查,是否类型有operator()?

时间:2017-02-27 08:11:54

标签: c++ c++11 templates sfinae

我有以下代码:

template <typename T>
struct function_traits
{
    typedef decltype(&T::operator()) test_type;
    typedef std::true_type res_type;
};

template <typename T>
struct function_traits
{
    typedef std::false_type res_type;
};

换句话说,我想知道type是否有operator()。我以为我可以用SFINAE方式来做到这一点。然而编译器告诉:

  

'function_traits':类模板已经定义。

此类代码有什么问题?

P.S。:这里的用法很简单:

auto f1 = [](const int a){ std::cout << a << std::endl; };
function_traits<decltype(f1)>::res_type;
auto f2 = false;
function_traits<decltype(f2)>::res_type;

编辑:我使用的是c ++ 11标准

2 个答案:

答案 0 :(得分:4)

在积极反馈的鼓励下,我会在这里发布一个简短的答案。

问题是你不能两次定义一个类,但你做了两次: -

operator()

C ++不允许这样做。

要检查某项功能是否存在,已有a question,您可以对其进行修改以支持#include <iostream> struct Hello { void operator()() { } }; struct Generic {}; // SFINAE test template <typename T> class has_parenthesis { typedef char one; typedef long two; template <typename C> static one test( decltype(&C::operator()) ) ; template <typename C> static two test(...); public: enum { value = sizeof(test<T>(0)) == sizeof(char) }; }; int main(int argc, char *argv[]) { std::cout << has_parenthesis<Hello>::value << std::endl; //print 1 std::cout << has_parenthesis<Generic>::value << std::endl; //print 0 return 0; }

这是一个演示,稍微修改一下Nicola Bonelli's answer

operator()

我几分钟前才知道它也适用于typeof

修改:我将decltype更改为slideDown,推荐 StoryTeller LmTinyToon 。感谢。

答案 1 :(得分:2)

使用void_t可能要简单得多:

template <typename T,class=void>
struct callable_without_args: std::false_type{};

template <typename T>
struct callable_without_args<T
          ,std::void_t<decltype(std::declval<T>()())>>
  :std::true_type{};

如果你的编译器提供 concepts

,它可能会更简单
template<T>
concept bool CallableWithoutArgs= requires(T&& a){
     (T&&)(a)();
};