2013-02-07 45 views
3

我一直在切換Template Factory函數以使用(並理解)std :: forward來支持右值並移動語義。我通常用於模板類的樣板工廠函數始終將參數標記爲const:您是否曾將C++ RValue引用參數標記爲const

#include <iostream> 
#include <utility> 

template<typename T, typename U> 
struct MyPair{ 
    MyPair(const T& t, const U& u):t(t),u(u){}; 

    T t; 
    U u; 
}; 

template<typename T, typename U> 
std::ostream& operator<<(std::ostream& os, const MyPair<T,U>& pair){ 
    os << "(" << pair.t << ")=>" << pair.u; 
    return os; 
} 

template<typename T, typename U> 
MyPair<T,U> MakeMyPair(const T& t, const U& u){ 
    return MyPair<T,U>(t,u); 
} 

using namespace std; 
int main(int argc, char *argv[]) {  

    auto no_forward = MakeMyPair(num, num); 
    std::cout << no_forward << std::endl; 

    auto no_forward2 = MakeMyPair(100, false); 
    std::cout << no_forward2 << std::endl; 
} 

按預期進行編譯。起初我轉換MakeMyPair也傳遞的參數爲const,但使用的XCode 4.6,這將不會在我的Mac編譯:

//$ clang --version 
//Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn) 
//Target: x86_64-apple-darwin12.2.0 
//Thread model: posix 


template<typename T, typename U> 
MyPair<T,U> MakeMyPair_Forward(const T&& t, const U&& u){ 
    return MyPair<T,U>(std::forward<const T>(t),std::forward<const U>(u)); 
} 

int main(int argc, char *argv[]) { 
    int num = 37; 
    auto anotherPair = MakeMyPair_Forward(num, true); //This won't work 

    auto allRvalues = MakeMyPair_Forward(73, false); //will compile 
    std::cout << allRvalues << std::endl; 
} 

沒有匹配的功能調用「MakeMyPair_Forward」候補 函數[與T = INT ,U =布爾]不可行:爲第一參數從 「INT」沒有已知的轉換爲「const int的& &」

這使得從http://en.cppreference.com/w/cpp/utility/forward感其中規定常數推導並我傳遞左值。

  • 如果到包裝器()的調用傳遞右值的std :: string,則T被推斷爲的std :: string(未的std :: string &,常量的std :: string &,或 性病:: string & &),並且std :: forward確保傳遞給foo的右值引用是 。
  • 如果對wrapper()的調用傳遞const lvalue std :: string,則T推導爲const std :: string &,而std :: forward確保將const 左值引用傳遞給foo。
  • 如果對wrapper()的調用傳遞一個非const的左值std :: string,則T被推斷爲std :: string &,而std :: forward確保將一個非const的 左值引用傳遞給foo 。

刪除const工程,因爲我想用rvalues和左值。只有傳遞rvalues作爲類型才能在MakeMyPair_Forward的參數上使用const。

//This works for rvalues and lvalues 
template<typename T, typename U> 
MyPair<T,U> MakeMyPair_Forward(T&& t, U&& u){ 
    return MyPair<T,U>(std::forward<const T>(t),std::forward<const U>(u)); 
} 

所以,這個問題。當作爲參數傳遞時,將右值引用標記爲const是否有意義?這不像我可以改變一個右值,這只是暫時的。通過修復和修復我的代碼後,我對編譯const的代碼感到有些驚訝。你爲什麼要將右值參數標記爲const?重點是隻提供一個需要rvalues的API嗎?如果是這樣,你會不會使用類型特徵來防止左值引用? https://stackoverflow.com/a/7863645/620304

謝謝。

+0

如果您不想修改它,那麼它是否是暫時的並不重要。 –

+0

我的想法是你不能修改它,因爲它是暫時的。所以標記爲const對我來說並不合適。 – Joel

+0

爲什麼你不能修改臨時? –

回答

6

所以,這個問題。當作爲參數傳遞時將右值引用 標記爲const是否有意義?

這裏是一處,這是在C++ 11標準完成:

template <class T> reference_wrapper<T> ref(T&) noexcept; 
template <class T> reference_wrapper<const T> cref(const T&) noexcept; 
template <class T> void ref(const T&&) = delete; 
template <class T> void cref(const T&&) = delete; 

即A const T&&用於捕獲所有右值,常量或不是,並將它們拋出編譯時錯誤,同時允許左值,即使const左值也可以綁定和工作。

現在這可能也可以用T&&enable_if約束完成。但是,如果在過去的幾十年中C++教會了我們的一件事:不要在語言設計中燒燬任何橋樑。 C++程序員通常會找到一種聰明的方式來使用最初認爲無用的語言功能。正是本着這種精神,const T&&才作爲合法選擇。

+0

這似乎是一個有效的用例。它也更容易閱讀,並且使用類型特徵可能會使其難以實現。我沒有想過刪除函數並使用delete關鍵字隱式創建構造函數。 – Joel

+2

只是,這些不是構造函數,而是刪除了命名空間範圍函數。 ** **是C++ 11中一個非常酷的新東西,一種禁用非成員函數的方法! :-)以前我們能做的最好的事情就是聲明並不定義它,延遲錯誤直到鏈接時間。 –

相關問題