2016-04-12 61 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

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

相關問題