基于参数函数参数类型的重载函数模板

时间:2016-04-12 17:39:55

标签: c++ templates c++11

我是一个看起来像这样的课程:

WebClient

我试图重载template<typename A> struct List { ... template<typename Fn, typename B = typename std::result_of<Fn(A)>::type> List<B> map(Fn f) const { ... } }; 并允许它接受类型为map的getter作为参数,以便我们可以A执行foos.map(&Foo::bar)bar类的吸气剂。以下功能有效:

Foo

但是如果我尝试使用相同的名称template<typename Fn, typename B = typename std::result_of<Fn(A*)>::type> List<B> mapGet(Fn getter) const { ... } ,编译器会抱怨它不明确。我的问题是,当map是吸气者时,前Fn失败,有效地禁用其中一个过载的std::result_of?另外,有没有办法让重载成为可能?

1 个答案:

答案 0 :(得分:1)

  

我的问题是,当Fn是getter时前者std::result_of会失败,有效地禁用其中一个重载的地图吗?

我猜“getter”你真正的意思是指向成员函数的指针?在这种情况下,std::result_of可以正常使用。假设我们有一些类型Foo

struct Foo {
    Foo(int i) : i(i) { }
    int bar() const { return i; }
    int i;
};

您可以按照预期使用指向成员的指针:

using T = std::result_of_t<decltype(&Foo::bar)(Foo )>;
static_assert(std::is_same<T, int>{}, "!");

唯一的区别是你实际上如何拨打f。对于C ++ 17,有std::invoke()可以使用所有可调用的类型,否则你可以直接使用std::bind()或编写自己的包装器来做同样的事情。

作为一个例子,忽略复制,转发和保留,我们可以像map那样写:

template <class A, class F, class B = std::result_of_t<F(A)>>
std::vector<B> map(std::vector<A> xs, F f)
{
    auto binder = std::bind(f, std::placeholders::_1);

    std::vector<B> r;
    for (auto& x : xs) {
        r.push_back(binder(x));
    }
    return r;
}

这对于实际的函数对象也是如此:

std::vector<int> vs{1, 2, 3, 4, 5};
std::vector<double> ds = map(vs, [](int i){return i * 2.0; });

正如我们的Foo指向成员的那样:

std::vector<Foo> foos{1, 2, 3, 4, 5};
std::vector<int> is = map(foos, &Foo::bar);