2016-04-12 64 views
1

我是一个类,看起来像这样:重载函数模板基于参数的函数参数类型

template<typename A> 
struct List { 
    ... 
    template<typename Fn, typename B = typename std::result_of<Fn(A)>::type> 
    List<B> map(Fn f) const 
    { ... } 
}; 

我想超载map,并允许它接受作为参数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失败,有效地禁用一个超载map?另外,有没有办法让超载成为可能?

回答

1

我的问题是,当Fn一吸气剂不会前者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); 
+0

目前在' mapGet'我做了'(x。* getter)()',其中'x'是列表的一个元素。我不确定我是否得到你;是否有可能超载'地图',然后呢? –

+0

@ZizhengTai你不需要两次'map'重载 - 唯一的区别是你在每个对象上调用'f'。所有其他的逻辑是一样的。 – Barry

+0

哦,我明白你的意思了! –

相关问题