2013-08-03 83 views
2

假設我有一個模板函數foo(),它將兩個整數引用作爲參數。我希望模板函數也可以自動處理常量引用(例如來自常量的引用)。這是一個通用的例子。我可以讓foo()工作,但是我必須爲每個參考/常量參考參數的排列提供一個新的實現。C++模板:使用const&爲常量參數自動重載模板化函數?

#include <iostream> 

using namespace std; 

template<typename A, typename B> 
void foo(A& a, B& b) 
{ 
    cout<<"a:"<<a<<" b:"<<b<<endl; 
} 

template<typename A, typename B> 
void foo(A& a, const B& b) 
{ 
    cout<<"a:"<<a<<" b:"<<b<<endl; 
} 

template<typename A, typename B> 
void foo(const A& a, B& b) 
{ 
    cout<<"a:"<<a<<" b:"<<b<<endl; 
} 

template<typename A, typename B> 
void foo(const A& a, const B& b) 
{ 
    cout<<"a:"<<a<<" b:"<<b<<endl; 
} 

int main() 
{ 
    int x = 0; 

    foo(x, x); 
    foo(x, 10); 
    foo(10, x); 
    foo(20, 20); 

    return 0; 
} 

上面的例子是有點人爲的,但它是我試圖做的一般化。在我更復雜的情況下,我有一個類作爲一組參數的包裝。類構造函數是模板化的,就像foo()一樣,並且可以有多達10個參數。枚舉所有2^10個可能的構造函數將是一場噩夢。

+0

我自我承認不是專家,但這個問題聽起來與完美的轉發有很大的關係(排列是一個不那麼細微的提示)。一個非常穩固的討論是在[這個問題]的主角 - 答案(http://stackoverflow.com/questions/3582001/advantages-of-using-forward),很值得你看看。 – WhozCraig

回答

1

如果模板是不會改變的參數,然後只是提供與const&的版本,你應該罰款:

template<typename A, typename B> 
void foo(const A& a, const B& b) 
{ 
    cout<<"a:"<<a<<" b:"<<b<<endl; 
} 

如果你傳遞一個非const左值,它仍然是綁定通過一個const引用,一切都會工作。

如果你想要一些重載來修改的參數,然後重新思考設計,那些好像不喜歡,就可以擁有一個名稱的功能。例如,對於結構內部成員的訪問器有例外,如果對象是const或者非const引用,您可能想要返回const&;否則......如果是這種情況,則可以採取相反的方式和僅提供非const超載:

template<typename A, typename B> 
void foo(A& a, B& b) 

在這種情況下,如果參數是一個臨時的還是非const參考,演繹類型將反映它,它會結合具有const&的論點。

int main() { 
    int a = 5; 
    const int b = 10; 
    foo(a,b);   // foo<int,const int>(int&,const int&) 
    foo(10,b);   // foo<const int,const int>(const int&, const int&) 
} 

重新讀你的問題似乎你可能有興趣在完美的轉發(這可能或不適合你的賬單)。如果是這種情況,並且如果您有C++ 11編譯器,那麼可以使用帶有可變參數模板的通用引用。構建一個好的包裝是一件很難的事,儘管你可能只需要使用std::tuple作爲實際的存儲,這應該使任務變得非常簡單。

+0

我決定讓所有東西都保持不變......然後把它扔掉。代碼編譯。這不是最安全的方法。一般來說,它永遠不會工作。但是,在這種特殊情況下,它是安全的,因爲還有其他安全防護措施可以防止堆棧臨時過早地超出範圍。我很欣賞C++ 11的建議。完美的轉發聽起來像是可以做到的。我們希望在一兩年內開始在我們的項目中支持它(等待第三方更新)。 – Glenn

3

您描述的問題是完美轉發問題。 C++ 11解決了這個問題universal references

template<typename A, typename B> 
void foo(A&& a, B&& b) { 
    bar(std::forward<A>(a), std::forward<B>(b)); 
} 

參數這裏沒有右值引用,但普遍引用。它們將具有與參數相同的引用和常量。

如果參數是右值,那麼在foo參數中將是帶名稱的右值。命名的rvalues是左值。要將參數傳遞給保留有效值的子函數,您需要將它們包裝在std::forward中。函數bar將獲得ab,其類型與foo完全相同。

0

除了發佈的所有答案都是正確的,這裏只是一個簡單的程序供您參考,因爲這可能會幫助您更好地理解這個概念。

#include<iostream> 
template<class X> 
void func(X& x, X& y) 
{ 
    //your code 
} 
template<class X, class Y> 
void intermediateFunc(X&& x, Y&& y) 
{ 
    func(x,y); 
} 

int main() 
{ 
    int y = 9; 
    intermediateFunc(5,5); 
    intermediateFunc(y,5); 
    intermediateFunc(5,y); 
    intermediateFunc(y,y); 
}