2013-05-04 79 views
5

我想傳遞一個參數(一個或多個)(一些具體類型的,說int)由R-或左值(常數)參考成員函數。我的解決方案是:右值或左值(常數)參考參數

#include <type_traits> 
#include <utility> 

struct F 
{ 
    using desired_parameter_type = int; 

    template< typename X, typename = typename std::enable_if< std::is_same< typename std::decay<X>::type, desired_parameter_type >::value >::type > 
    void operator() (X && x) const 
    { 
     // or even static_assert(std::is_same< typename std::decay<X>::type, desired_parameter_type >::value, ""); 
     std::forward<X>(x); // something useful 
    } 
}; 

另一個例子是http://pastebin.com/9kgHmsVC

但實在是太冗長。如何以更簡單的方式做到這一點?

也許我應該使用std::remove_referencestd::remove_const而不是std::decay的疊加,但這裏只是簡化。

+0

rvalue傳遞簡單類型如'int'沒有意義。在更一般的情況下,我相信C++ 11有一個特殊情況,其中右值參數將被讀作右值或左值參數。儘管如此,我不記得確切的情況。 – Dave 2013-05-04 16:38:40

+0

所以你希望'x'是一個右值引用(如果通過右值引用)或左值引用給'const'?我是否正確理解,X &&不會被你接受,因爲當左值被傳遞時,它將是對非''constst'的左值引用? – 2013-05-04 16:41:22

+0

嗯,我們走吧,我相信你正在努力做到這一點:http://thbecker.net/articles/rvalue_references/section_07.html這是在下一頁使用rvalues解釋。如果我誤解了這個問題,大叫大叫。 – Dave 2013-05-04 16:41:40

回答

4

如果我正確理解你的問題,你希望有一個函數的參數是右值引用(如果提供右值)或左值引用const(在提供左值的情況下)。

但是會這個功能呢?那麼,因爲它必須能夠處理這兩種情況,包括提供左值的情況下,它不能修改它的輸入(至少不是綁定到x參數的那個) - 如果是這樣,它會違反語義const參考。

但話又說回來,如果它不能改變參數的狀態,沒有任何理由允許右值引用:寧可讓x是左值參考const所有的時間。對const的左值引用可以綁定到右值,因此您將被允許傳遞右值和左值。

如果函數的語義是不同的依據是什麼獲得通過,那麼我會說這更有意義,寫這樣的功能:一個接受一個右值引用,而另一種左值參考const

+0

constness是可選的(所有'&&','&','const'都允許) – Orient 2013-05-04 16:53:06

+1

@Dukales:我不明白:(你是什麼意思?如果函數必須能夠使用'const'這意味着它不會嘗試修改'x'。但是,這意味着您不需要右值引用 – 2013-05-04 16:54:17

+0

您是否瞭解元編程?讓我們假設,那些被傳遞參數的函數將決定如何處理(如何分配)它們的特定「參考性」和常量。 – Orient 2013-05-04 16:59:43

1

正如Andy所提到的,這裏最重要的是你可以在你的函數內部這是有意義的。

  • 你可以把參數傳遞給另一個函數。在這種情況下,使用模板並不重要,因爲如果給出了錯誤的參數類型,它仍然會產生編譯錯誤(發送到第二個函數的錯誤類型)。您可以使用template <typename T> blah (T && x)
  • 還有什麼需要你寫取決於它是否是一個R-或1-參考值不同的代碼,所以你需要這麼寫兩個功能:blah (const int & x)blah (int && x)

我假設你必須嘗試第一個選項,並試圖使任何潛在的編譯器錯誤更加用戶友好。那麼,我會說這不值得;程序員仍然會在任何像樣的編譯器輸出中看到「被......調用」列表。

+0

在該函數下可以表示具有大量初始化列表的ctor。 – Orient 2013-05-04 17:07:17

+0

@Dukales:但這只是轉發,所以你可以使用模板,如果錯誤地調用,仍然會出現編譯錯誤。 – Dave 2013-05-04 17:09:29

1

其實,這是一個非常好的問題。到目前爲止,我還一直在使用通用參考技巧加上enable_if錘子。在這裏,我提出了一個不使用模板並使用左值轉換作爲替代方案的解決方案。

下面是其中的情況出現使用就地ofstream使用已知的例子是不可能的(或很難)在C++ 98的真實例子(我用ostringstream在這個例子中,以使其更清晰)。

首先,您將在C++ 98中看到一個關於左值引用的函數。

#include<iostream> 
#include<sstream> 
struct A{int impl_;}; 

std::ostringstream& operator<<(std::ostringstream& oss, A const& a){ 
    oss << "A(" << a.impl_ << ")"; // possibly much longer code. 
    return oss; 
} 
// naive C++11 rvalue overload without using templates 
std::ostringstream& operator<<(std::ostringstream&& oss, A const& a){ 
    oss << "A(" << a.impl_ << ")"; // ok, but there is code repetition. 
    return oss; 
} 

int main() { 

    A a{2}; 
    {// C++98 way 
     std::ostringstream oss; 
     oss << a; 
     std::cout << oss.str() << std::endl; // prints "A(2)", ok" 
    } 
    {// possible with C++11, because of the rvalue overload 
     std::cout << (std::ostringstream() << a).str() << std::endl; //prints "A(2)", ok 
    } 
} 

正如您在C++ 11中看到的,我們可以實現我們在C++ 98中無法實現的功能。那就是利用ostringstream(或ofstream)就地。現在出現OP問題,兩個重載看起來非常相似,都可以加入一個?

一種選擇是使用通用參考(Ostream&&),並且可選地使用enable_if來限制類型。不是很優雅。

我發現通過使用這個「真實世界」的例子是,如果想要使用相同的代碼左值參考和右值ref是因爲可能你可以將一個轉換爲另一個!

std::ostringstream& operator<<(std::ostringstream&& oss, A const& a){ 
    return operator<<(oss, a); 
} 

這看起來像一個無限遞歸函數,但它不是因爲oss是一個左值引用(是的,它是一個左值引用,因爲它有一個名字)。所以它會調用其他的超載。

您仍然需要編寫兩個函數,但其​​中一個代碼不需要維護。總之,如果「有意義」將函數同時應用於(非常量)左值引用和右值,這也意味着您可以將右值轉換爲左值並因此轉發給單個函數。請注意,「它有意義」取決於上下文和預期代碼的含義,而且我們必須通過明確地調用左值過載來「告知」編譯器。

我並不是說這比使用通用參考更好,我認爲它是一種替代方法,可以證明其意圖更加清晰。

可編輯代碼:http://ideone.com/XSxsvY。 (歡迎反饋)