for 在C++ 11中省略返回類型




lambda expressions c++ 11 (6)

我同意Yttrill。 返回類型推導已經被證明是像Haskell這樣的語言的可行實踐,並且由於C ++已經實現了'auto',它只是進一步實現返回類型推導。 這種推論應該在專業化時發生,而不是模板定義,因為需要提供給模板的真實類型的信息。 聲明和定義的分離不再是通用C ++中的常見做法,因為模板體必須寫在頭文件中,因此模板體幾乎總是使用模板聲明。 在存在多個返回語句並且它們的類型不匹配的情況下,編譯器可以愉快地報告錯誤。 總之,如果委員會願意,在C ++中完全可以使用返回類型推導。 並且它非常重要,因為手動編寫返回類型的重複阻礙了小型通用輔助函數的普遍使用,這在功能和通用編程中是常見的做法。

我最近發現自己在C ++ 11模式下使用gcc 4.5的以下宏:

#define RETURN(x) -> decltype(x) { return x; }

並編寫如下函數:

template <class T>
auto f(T&& x) RETURN (( g(h(std::forward<T>(x))) ))

我一直這樣做是為了避免不得不有效地編寫函數體兩次,並保持身體和返回類型的同步(這在我看來是等待發生的災難)的不便。

問題是這種技術只適用於一行功能。 所以當我有這樣的事情時(複雜的例子):

template <class T>
auto f(T&& x) -> ...
{
   auto y1 = f(x);
   auto y2 = h(y1, g1(x));
   auto y3 = h(y1, g2(x));
   if (y1) { ++y3; }
   return h2(y2, y3);
}

然後我必須在返回類型中添加一些可怕的東西。

此外,每當我更新函數時,我都需要更改返回類型,如果我沒有正確更改它,如果我很幸運,我會收到編譯錯誤,或者更壞的情況下會出現運行時錯誤。 必須將更改複製並粘貼到兩個位置並保持同步,我覺得這不是一個好習慣。

而且我想不出一種情況,我希望在返回時使用隱式強制轉換而不是顯式強制轉換。

當然有一種方法可以要求編譯器推斷出這些信息。 編譯器保守秘密有什麼意義? 我認為C ++ 11的設計不需要這樣的複制。


編輯:oops,我剛剛意識到trailing-return-type說明符和return語句之間存在範圍差異。 特別:

auto f(int a)
{
    char r[sizeof(f(a))+1];
    return r;
}

KABOOM!

上一個答案:

遺憾的是,在這種情況下,語言沒有提供編譯器推斷返回類型的語法,因為顯示推理是可能的很簡單。

具體來說,我們討論的是函數中只有一個return語句的情況。

與返回語句的函數位置或前面的代碼有多複雜無關,應該清楚以下轉換是可能的:

return (ugly expression);

auto return_value = (ugly expression);
return return_value;

如果編譯器可以推斷return_value的類型(並且根據C ++ 0x規則,它可以),那麼可以選擇推斷類型的return_value作為函數的返回類型。

因此,在我看來,對C ++ 0x進行修改時,只有在返回語句的多重性不是一個時才需要尾隨返回類型說明符才是可行的並且可以解決問題。


這種行為的基本原理在草案8.3.5p12中給出:

對於在declarator-id之前指定更複雜的類型,trailing-return-type最有用:

template <class T, class U> auto add(T t, U u) -> decltype(t + u);

而不是

template <class T, class U> decltype((*(T*)0) + (*(U*)0)) add(T t, U u);

所以這實際上只是為了簡化引用參數名稱有幫助的情況。

如果你假設C ++ 能從函數體中推斷函數的返回類型:這不會飛。 C ++(和C)的目標是通過將聲明與實現分離來實現模塊化,因此在調用時,您可能沒有可用的函數體。 但是,每個調用者都需要知道所調用的每個函數/方法的參數類型和返回類型


您的退貨類型是否真的經常改變? 為什麼不能明確指定它? 例:

template<class T>
int f(T&& x)
{
...
}

人們做了二十多年......


如果您只是嘗試設置返回類型,請將其設置為模板參數。 這樣,您可以更改與返回類型相關的所有內容,而無需實際更改功能。 如果您希望在此示例中使用,則可以設置默認返回類型。

template <class R = int, class T>
R f(T&& x)
{
   ...
   return h2(y2, y3);
}

下面的代碼證明了它的有效性。

演示代碼:

#include <iostream>
#include <iomanip>

template <class T, class S>
T h2(T& x, S& y)
{
  return x + y;
}

template <class R = int, class T>
R f(T& x)
{
  auto y2 = x;
  auto y3 = x;
  return h2(y2, y3);
}

int main(int argc, char** argv)
{
  int x = 7;
  std::string str = "test! ";

  auto d = f<double>(x);
  auto i = f(x); // use default type (int)
  auto s = f<std::string>(str);

  std::cout << std::fixed << std::setprecision(4);
  std::cout << "double: " << d << std::endl;
  std::cout << "int: " << i << std::endl;
  std::cout << "string: " << s << std::endl;

  return 0;
}

OUTPUT:

double: 14.0000
int: 14
string: test! test!

不幸的是,您正在尋找的確切功能尚未存在,並且不是C ++ 0x規範的一部分。 但是,在草擬時,這可能是C ++ 1x規範的一部分。 在那之前,堅持模板。


似乎g ++ 4.8正在實現自動返回類型推導。 這個補丁由傑森·梅里爾(Jason Merrill)投入,他也在發送C ++的論文 - 1Y用於該功能。 該功能可用-std = c ++ 1y。

還在玩它。







return-value