我剛剛了解了 C 中的結構化系結,但有一件事我不喜歡
auto [x, y] = some_func();
是auto被隱藏的型別x和y。我必須查找some_func的宣告才能知道xand的型別y。或者,我可以寫
T1 x;
T2 y;
std::tie(x, y) = some_func();
但這僅適用于,如果x和y是默認可構造的而不是const。有沒有辦法寫
const auto [x, y] = some_func();
對于非默認constructible型別x和y的方式,使得該型別x和y可見?編譯器最好在我宣告x并且y作為與some_func的回傳型別不兼容的東西時抱怨,即 not const auto /* T1, T2 */ [x, y] = some_func();。
澄清。由于我的問題下方的評論似乎圍繞是否使用&,并且之前的一些答案將我的問題誤解為“使用哪種語法來提取回傳對的資料型別”,我想我需要澄清我的問題。
假設我們的代碼分布在多個檔案中
//
// API.cpp
//
#include <utility>
class Foo {
public:
Foo () {}
};
Foo foo;
class Bar {
private:
Bar () {}
public:
static Bar create () { return Bar(); }
};
Bar bar = Bar::create();
std::pair<int, bool> get_values () {
return std::make_pair(73, true);
}
std::pair<Foo&, Bar&> get_objects () {
return std::pair<Foo&, Bar&>(foo, bar);
}
//
// Program.cpp
//
int main (int, char**) {
const auto [x, y] = get_values();
const auto& [foo, bar] = get_objects();
/* Do stuff with x, y, foo and bar */
return 0;
}
在撰寫這段代碼時,我對get_values和的宣告get_objects很新鮮,所以我知道它們的回傳型別。但是Program.cpp一星期后看的時候我幾乎不記得代碼了,main更不用說它的變數的資料型別或get_valuesand的回傳型別了get_objects,所以我需要打開API.cpp并查找get_values并get_objects知道它們的回傳型別。
我的問題是是否有語法寫的變數的資料型別x,y,foo并bar在main進入結構化的結合?最好以一種允許編譯器糾正我的方式,如果我犯了錯誤,所以沒有評論。類似的東西
int main (int, char**) {
// Pseudo-Code
[const int x, const bool y] = get_values();
[const Foo& foo, const Bar& bar] = get_objects();
/* Do stuff with x, y, foo and bar */
return 0;
}
uj5u.com熱心網友回復:
沒有機制可以在結構化系結宣告中宣告“變數”的型別。如果您希望型別名稱可見,則必須放棄結構化系結宣告的便利性。
這很重要,因為結構化系結的作業方式。x并且y本身并不是真正的變數。它們是訪問結構化系結陳述句存盤的物件組件的替代品。它們是由宣告捕獲的物件的組件。只有一個實際變數:auto推導出的未命名變數。您宣告的名稱只是該物件的組成部分。
理解了這一點,現在考慮以下陳述句:int i = expr;只要expr可以轉換為int.
如果您可以將型別名放在結構化系結宣告中,人們也會有同樣的期望。他們希望如果函式回傳 a tuple<float, int>,他們可以在auto [int x, int y]. 但是他們不能,因為被存盤的物件是 a tuple<float, int>,它的第一個成員是 a float。編譯器將不得不發明一些包含兩個ints 的新物件并進行轉換。
但這很危險,尤其是在處理包含參考的回傳值時。理論上你可以把 atuple<float&, int>變成 a tuple<int, int>。但它不會具有相同的含義,因為您不能修改被參考的物件。
但同樣,用戶希望變數宣告能夠進行此類轉換。用戶一直依賴它。取消這種權力只會在功能中造成混亂。
所以該功能不會這樣做。
uj5u.com熱心網友回復:
如果您想保留結構化系結和隨之而來的可能優化,最簡單的方法是放置一個表示型別的注釋。顯然,如果回傳型別發生變化會很糟糕:評論會變得誤導。手動撰寫型別時,這會導致編譯時錯誤。
要模仿這種行為,您可以手動強制編譯時錯誤:
#include <type_traits>
auto [x, y] = some_func();
static_assert(std::is_same_v<decltype(x), const my_type>);
static_assert(std::is_same_v<decltype(y), some_other__type>);
它將顯示型別資訊,如果型別碰巧不是您所期望的,則強制編譯時錯誤,甚至防止發生不需要的轉換。不再意外分配long給int.
或者:使用可以顯示區域變數及其型別的 IDE。
uj5u.com熱心網友回復:
你可以這樣做:
#include <iostream>
#include <tuple>
auto func( )
{
int x = 5;
double y = 5.5;
std::cout << "Executing the func..." << '\n';
return std::make_tuple<int, double>( std::move( x ), std::move( y ) );
}
int main()
{
const auto returnVal = func( );
const int& x = std::get<0>( returnVal );
// const unsigned int& x = std::get<0>( returnVal ); // replace this with the upper one and
// it will provoke a compile-time error
const double& y = std::get<1>( returnVal );
// const char& y = std::get<1>( returnVal ); // replace this with the upper one and
// it will provoke a compile-time error
static_assert( std::is_same_v< decltype( x ), decltype( std::get<0>( returnVal ) ) > &&
std::is_same_v< decltype( y ), decltype( std::get<1>( returnVal ) ) >, "Wrong types used" );
std::cout << x << " " << y << '\n';
return 0;
}
如您所見,這可以替代結構化系結。x和y是對回傳值的參考。在閱讀源代碼時,您確實可以明確地看到它們的型別。如果你用錯誤的型別宣告它們,那么編譯器會抱怨(例如,const char& y而不是const double& y)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/373619.html
下一篇:容器初始化中的模板型別推導
