2010-08-07 59 views
11

tuple in boost以及TR1/C++ 0x爲從函數返回兩個值提供了一個方便(用於函數的作者)方法 - 但是它似乎如何用C++中的多個返回值進行初始化(0x)

T happy(); 
const auto meaningful_name(happy()); // RVO means no excess copies 

但:

tuple<T,U> sad(); 

我們要麼必須交出挑一的能力,簡單地使用功能初始化變量的能力:呼叫者的語言傷害其一大特色我們的返回值有意義的名稱,並使用get<n>()無處不在:

const auto two_unrelated_things(sad()); 

或作臨時:

const auto unwanted_named_temporary(sad()); 
const auto one_name(get<0>(unwanted_named_temporary)); 
const auto two_name(get<1>(unwanted_named_temporary)); 

或初始化分配,僅當該類型分配工作的切換,並打破auto

tuple_element<0, decltype(sad())>::type one_mutable; // there might be a less 
tuple_element<1, decltype(sad())>::type two_mutable; // verbose way 
tie(one_mutable,two_mutable) = sad(); 

或對本地班級做一些不自然的事情:

const struct ugh { 
    ugh(decltype(sad()) rhs) : one_name(get<0>(rhs)), two_name(get<1>(rhs)) {} 
    const tuple_element<0, decltype(sad())>::type one_name; 
    const tuple_element<1, decltype(sad())>::type two_name; 
} stuff(sad()); // at least we avoid the temporary and get initialization 

有沒有更好的方法?我使用上面的VC10兼容構造,將完全C++ 0x或提升幫助?

理想的情況下它會:

  • 允許我使用初始化,而不僅僅是分配
  • 呼叫者挑名字返回,到變量
  • 沒有作出額外的副本
  • 爲堆棧變量和類成員工作
  • 可能是一個大型的瘋狂模板庫,但對調用者和函數編寫者
+2

有趣的問題,雖然我沒有看到如何在單個表達式中定義不同類型的變量。 - 如果將命名變量更改爲引用(避免複製),我認爲「或創建臨時」選項可能是正確的。 – UncleBens 2010-08-07 08:33:42

+0

關於引用的好處 - 我認爲這是一個堆棧變量的解決方案。 我試圖做同樣的一類: C類{ 市民: C()SR(SAD()),一個(讓<0>(SR)),二(獲得<1>(SR)){} const T & one; const U & two; private: tuple sr; } 但它看起來像在VC10中,C是兩個大於元組的指針,不是一個巨大的交易,而是一種跛腳 - 編譯器認識到引用是別名而不是分配空間是合法的在他們的情況下?這不就是爲什麼指向引用的指針首先是非法的嗎? – BCoates 2010-08-07 09:24:16

+0

對於一個類,如果數據存儲爲一個元組,則可以只提供一個名爲accessor的方法,它調用相應的'get '。我懷疑將會有一個「瘋狂的模板」的解決方案,因爲核心語言似乎並不支持你所要求的。也許你可以減少你必須輸入宏的字符數... – UncleBens 2010-08-07 09:38:48

回答

2
std::tuple<Type1, Type2> returnValue = sad(); 
Type1& first = std::get<0>(returnValue); 
Type2& second = std::get<1>(returnValue); 

我不知道你的第四子彈手段,但滿足所有的休息。

*編輯:根據你上面的評論,我想出了你的意思是第四個子彈。

struct Object { 
    Object(const std::tuple<Type1, Type2>& t) : value(t) { } 
    Type1& First() { return std::get<0>(value); } 
    Type2& second() { return std::get<1>(value); } 
private: 
    std::tuple<Type1, Type2> value; 
} 

根據需要進行修改。

如果返回的值非常不相關,那麼您也可以根本不使用std::tuple,因此您必須將它們拆分以便合理使用它們。人們多年來一直在返回struct s,其中包含合理命名的字段,或者接受輸出的參考參數。

順便說一句,你似乎愛上了auto。不要。它的一個很好的功能,但這是而不是它應該使用的方式。如果您不時指定類型,您的代碼將變得難以辨認。

+0

當我想到「班級成員」時,這種情況甚至可以讓你刪除所有的副本嗎?我認爲在任何情況下你都會至少複製一次「價值」,這顯然需要至少複製一次它的成員。所以你可能不如直接存儲這些值,而忘記存儲元組。 – 2010-08-07 10:07:45

+0

我同意在不合適的時候使用'std :: tuple' - 我只是擔心它會變得習慣用法,並且使代碼變得不那麼容易理解,而且完全可以得到'(sometuple)' ,看起來我太擔心額外的副本:當sad()返回make_tuple(...)時,構造函數中的'tie(a,b)= sad()'成功地忽略了所有的元組成員副本。 。 也許這個教訓是「'const'數據成員是一件麻煩事」。 – BCoates 2010-08-07 11:33:02

+1

@bcoates:關於元組的錯誤和過度使用。當標準庫表示範圍爲'pair '時,標準庫本身有點兒內疚。 OTOH,boost正在使用一個更好的替代方法:'iterator_range '帶'begin()'和'end()'方法。一個範圍不是一個抽象的對,「第一」和「第二」確實有一個具體的含義! - 我不認爲應該用非泛型代碼來開心。 – UncleBens 2010-08-07 12:01:48