3

假设我有类型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;
};

但这不起作用(没有检测到正确的匹配)。怎么了?

4

2 回答 2

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;
};

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

于 2013-03-01T18:11:40.273 回答
2

std::result_of<test(Arg const&)>提供一个模板参数,它是一个函数类型,它引用Arg const并返回一个test. 所以它type不是test很有帮助。

请注意,正如所写,需要代码

bar b;
foo f;
b(f);

要有效实际上是 5 个要求: bar并且foo每个都有一个可访问的默认构造函数和析构函数,并且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

于 2013-03-01T18:18:33.070 回答