2017-05-08 86 views
0

我正在嘗試編寫一個函數,該函數基本上將一個類型模板化的類的實例轉換爲第二個類型模板化的同一類的實例。我想避免在調用函數時顯式聲明模板類型。從lambda的模板參數演繹

這裏是什麼,我試圖做一個最小的編譯例子:

template<class T> class container {}; 

template <class A, class B, template <class C> class Container> 
Container<B> transform(Container<A> c, B(func)(A)) 
{ 
    return Container<B>{}; 
} 

int do_something(int in) 
{ 
    return in + 1; 
} 

int main() 
{ 
    container<int> c{}; 

    //this one doesn't work: 
    //transform(c, [](int in) -> int { return in + 1; }); 
    //these are fine: 
    transform<int, int>(c, [](int in) -> int { return in + 1; }); 
    transform(c, do_something); 

    return 0; 
} 

在取消了編譯錯誤的第一transform通話效果:

的Visual Studio 2017年:

error C2784: 'Container<B> transform(Container<A>,B (__cdecl *)(A))': could not deduce template argument for 'B (__cdecl *)(A)' from 'test::<lambda_afc081691b59f849887abca17e74b763>' 

無論克版本++ coliru.stacked-crooked.com默認使用:

main.cpp:4:14: note: template argument deduction/substitution failed: 
main.cpp:18:52: note: mismatched types 'B (*)(A)' and 'main()::<lambda(int)>' 
    transform(c, [](int in) -> int { return in + 1; }); 
               ^

這是否意味着編譯器不可能推導出lambda的簽名,即使它已被明確定義爲這樣?

我知道我可以重寫我的變換函數是這樣的:

template <class A, template <class C> class Container, class F> 
auto transform(Container<A> c, F func)->Container<decltype(func(A{}))> 
{ 
    return Container<decltype(func(A{}))>{}; 
} 

但現在的函數簽名是有點不太可讀的錯誤信息,如果我提供一個不恰當的功能我得到的是相當不友好。使用std::function<B(A)>也沒有幫助。

有沒有一種方法來使用更緊密指定的函數參數與lambdas和沒有明確添加模板類型?

回答

2

您需要捕捉少拉姆達轉換成瓶坯操作的靜態函數。該轉換實際上可以通過運算符的一元運算符相當容易地調用。

transform(c, +[](int in) -> int { return in + 1; }); 

由於捕獲更少的λ的閉合類型具有轉換操作者ret(*)(params),編譯器會遇到+時調用它。這是因爲您實際上可以將+應用於指針類型。

[expr.unary.op/7]

一元+運算的操作數應具有算術,無作用域枚舉,或指針類型,結果是論證的值。整型提升在整型或枚舉操作數上執行。結果的類型是提升操作數的類型。

+0

我從來沒有聽說過的'+'的把戲了。俏皮。 Coliru的g ++會接受這一點,但VS2015和VS2017失敗時會出現一個有趣的''operator +'模糊不清的錯誤,無法區分''和'',所以不幸的是我無法使用這個把戲。 – Rook

+0

@Rook - 當然MSVC會拒絕它......對不起,我不知道如何解決這個問題。 – StoryTeller

+0

既然參數是一個函數,不應該將lambda轉換爲函數指針隱式發生? – bolov

1

BA不能在B(func)(A)從拉姆達推斷出來。

你可能會改變你的模板更通用的,是這樣的:

template <template <typename...> class Container, typename Ts...> 
auto transform(const Container<Ts...>& c, F f) 
-> Container<std::decay_t<decltype(f(*c.begin())>> 
{ 
    return {}; 
} 
相關問題