2015-09-04 77 views
1

我想知道是否可以在類型上使用某些約束來進行轉發,以便可以自動執行重載。例如,假設我有以下基本函數:使用std :: forward重載函數轉發

int f(A a, B b) 
{ 
    return g(a) + h(b); 
} 

其中AB是包含所有適當的複製和移動構造函數的類,和gh是函數的每一個具有兩個重載:int g(const A&)int g(A&&) ,和h一樣。通常的方式轉發abf

template <typename T1, typename T2> 
int f(T1&& a, T2&& b) 
{ 
    return g(std::forward<T1>(a)) + h(std::forward<T2>(b)); 
} 

不過,我想也添加另一種方式來使用此功能:如果我嘗試使用轉發與此重載

int f(B b, A a) 
{ 
    return g(a) + h(b); 
} 

,生成的模板函數會這樣:

template <typename T1, typename T2> 
int f(T1&& b, T2&& a) 
{ 
    return g(std::forward<T1>(a)) + h(std::forward<T2>(b)); 
} 

它將與第一個模板發生衝突。

所以我的問題是,當我寫一個模板函數轉發,我能約束T1T2,這樣在第一超載,T1只能綁定到const A&A&&,而第二個重載可以觸發如果T1const B&B&&

沒有這樣的機制,我需要明確地寫8個重載。

注:我想我也許能在這個玩具爲例做了一些模板的東西(有點討厭)從type_traits,但我想第一個知道,如果有一個更簡單的方法,因爲在現實中,過載可比這個玩具的例子更多不同。

回答

4

我可以約束T1和T2,以便在所述第一過載,T1可以僅結合const A&A&&

是的。這個概念被稱爲SFINAE(Substituation失敗不是一種錯誤),基本上是這樣的:

template <typename T1, typename T2, 
      std::enable_if_t<std::is_same<A, std::decay_t<T1>>::value>* = nullptr 
      > 
int f(T1&& a, T2&& b); 

如果T1不「衰變」到A,那麼enable_if_t<>類型會形成不良的,這超載將被拋出。

如果說的太詳細,你可以寫一個別名:

template <typename From, typename To> 
using enable_if_decays = std::enable_if_t<std::is_same<To, std::decay_t<From>>::value>; 

template <typename T1, typename T2, 
      enable_if_decays<T1, A>* = nullptr> 
int f1(T1&& a, T2&& b); 

template <typename T1, typename T2, 
      enable_if_decays<T1, B>* = nullptr> 
int f1(T1&& b, T2&& a); 

// etc. 
+0

這是否阻止我做出另一個超載? – Tunococ

+0

我認爲這是隱含的。然後我會添加它。 – Tunococ

+0

@Tunococ沒有什麼能夠阻止你再次造成超負荷 - 你只需要確保它不會含糊不清。 – Barry

1

的其他可能性是獲取正確的參數根據其類型

template <typename T1, typename T2> 
int f(T1&& t1, T2&& t2) 
{ 
    auto t = std::forward_as_tuple(t1, t2); 
    return g(my_get<A>(t)) + h(my_get<B>(t)); 
} 

my_get<T>類似於std::get<T>(TUPLE&),但取決於元組內容類型檢索T&&T&

+0

+1好的比例。不幸的是,當一些參數具有相同類型時不起作用。 –

+0

@NikkiChumakov:我們仍然可以通過'my_get '來檢索元組中的'i'th'T'。 – Jarod42

+0

我能創造my_get 執行該副本在返回的元素:http://melpon.org/wandbox/permlink/lWtHqXgEyVrB4y8v但我無法實現的完美轉發,根據T1,T2類型。想象一下函數「h(int&i){...}」,我們在輸入處有std :: tuple 。 my_get <1, int>可能應該將引用不返回到中間元素,而是返回到最後一個元組的元素。但是對我來說,這樣做實在太困難了。 –