如何检查成员运营商(类型)?

时间:2013-03-01 17:32:10

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

假设我有barfoo类型。如何构建模板类has_call_with_arg<>,使得当{且仅当

has_call_with_arg<bar,foo>::value为真
bar b;
foo f;
b(f);

会编译吗?我查看了各种相关问题(包括上面提到的)并尝试了

template<typename Func, typename Arg>
class has_call_with_arg
{
  struct bad {};
  struct test : Func
  {
    template<typename C>
    bad operator()(C const&r);
  };
public:
  static const bool value = 
    !std::is_same<bad, typename std::result_of<test(Arg const&)>::type >::value;
};

但是没有用(没有检测到正确的匹配)。怎么了?

2 个答案:

答案 0 :(得分:3)

template<typename sig, typename functor> struct is_callable;
template<typename Ret, typename... Arg, typename functor> 
struct is_callable<Ret(Arg...), functor> { // partial spec
private:
    struct no {};
public:
    template<typename U> static auto f(std::nullptr_t) -> decltype(std::declval<U>()(std::declval<Arg>()...));
    template<typename U> static no f(...);
    static const int value = std::is_convertible<decltype(f<functor>(nullptr)), Ret>::value;
};

我创建了这个内容for my tutorials,它解释了这个特征的构造(首先是非可变形式)。

答案 1 :(得分:2)

std::result_of<test(Arg const&)>提供模板参数,该参数是引用Arg const并返回test的函数类型。所以它的typetest,不太有帮助。

请注意,如上所述,需要代码

bar b;
foo f;
b(f);

有效是5个要求:barfoo每个都有一个可访问的默认构造函数和析构函数,b(f)是一个有效的表达式。我将专注于最后一个(这可能是你的意思)。如果您确实是指其他部分,则可以使用标准<type_traits>属性添加这些部分。

函数std::declval非常适合假装你有一个给定类型的对象,即使你没有。它绝不能被调用,所以它通常只在decltype表达式中使用。

有两种基本的方法可以实现SFINAE技巧,基于两个地方C ++允许模板参数推断失败,只是丢弃失败的声明:

首先,尝试匹配类部分特化:

template<typename Func, typename Arg, typename Enable = void>
struct has_call_with_arg1 : public std::false_type {};

template<typename Func, typename Arg>
struct has_call_with_arg1<Func, Arg,
    decltype(std::declval<Func&>()(std::declval<Arg&>()))>
    : public std::true_type {};

其次,当至少一个重载是函数模板时,重载解析。 (类模板的非模板成员函数在这里不起作用,因为实例化类需要每个成员声明都有效。)

namespace has_call_with_arg_impl {
    template<typename F, typename A>
    std::true_type test(decltype(std::declval<F&>()(std::declval<A&>()))*);

    template<typename F, typename A>
    std::false_type test(...);
}

template <typename Func, typename Arg>
struct has_call_with_arg2
    : public decltype(has_call_with_arg_impl::test<Func,Arg>(nullptr)) {};

演示:http://ideone.com/KgRI8y