簡體   English   中英

rvalue或lvalue(const)引用參數

[英]rvalue or lvalue (const) reference parameter

我想通過r-或l-值(const)引用將參數(一些具體類型,比如int )傳遞給成員函數。 我的解決方案是:

#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 ,但這里只是簡化。

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

但是這個功能會做什么? 好吧,因為它必須能夠處理這兩種情況,包括提供左值的情況,它不能修改它的輸入(至少不是綁定到x參數的那個) - 如果確實如此,它將違反語義const參考。

但話又說回來,如果它不能改變參數的狀態,就沒有理由允許rvalue引用:而是讓x一直是對const的lvalue引用。 const左值引用可以綁定到rvalues,因此您將被允許傳遞rvalues和lvalues。

如果函數的語義根據傳遞的內容而不同,那么我會說編寫兩個這樣的函數更有意義:一個采用右值引用,另一個采用左值引用const

正如Andy所提到的,重要的是你在函數中實際可以做的事情是有意義的。

  • 您可以將參數轉發給另一個函數。 在這種情況下,使用模板並不重要,因為如果給出了錯誤的參數類型,它仍然會產生編譯錯誤(錯誤的類型發送到第二個函數)。 您可以使用template <typename T> blah (T && x)
  • 其他任何東西都要求你根據它是r值還是l值引用來編寫不同的代碼,所以你需要編寫2個函數: blah (const int & x)blah (int && x)

我假設您必須嘗試第一個選項,並且您嘗試使任何潛在的編譯器錯誤更加用戶友好。 好吧,我說這不值得; 程序員仍然會在任何體面的編譯器的輸出中看到“被...調用”列表。

實際上,這是一個非常好的問題。 到目前為止,我一直在使用通用引用技巧和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來約束類型。 不是很優雅。

我通過使用這個“真實世界”的例子發現,如果想為lvalue ref和rvalue ref使用相同的代碼是因為可能你可以將一個轉換為另一個!

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

這看起來像一個無限遞歸函數,但它不是因為oss是左值引用(是的,它是左值引用,因為它有一個名稱)。 所以它會調用另一個重載。

您仍然需要編寫兩個函數,但其​​中一個函數具有您不必維護的代碼。

總之,如果“有意義”©將函數應用於(非常量)左值引用和右值,這也意味着您可以將右值轉換為左值,因此轉發到單個函數。 請注意,“它有意義”取決於上下文和預期代碼的含義,並且我們必須通過明確地調用左值重載來“告訴”編譯器。

我並不是說這比使用普遍參考更好,我說它是另一種選擇,可以說它的意圖更清楚。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM