web-dev-qa-db-ja.com

末尾の戻り型の構文スタイルを新しいC ++ 11プログラムのデフォルトにする必要がありますか?

C++ 11は、新しい関数構文をサポートしています。

auto func_name(int x, int y) -> int;

現在、この関数は次のように宣言されます。

int func_name(int x, int y);

新しいスタイルはまだ広く採用されていないようです(gcc stlなど)

しかし、この新しいスタイルは新しいC++ 11プログラムのどこでも優先されるべきですか、それとも必要なときにだけ使用されるのでしょうか?

個人的には、可能な場合は古いスタイルを好みますが、スタイルが混在するコードベースはかなりいように見えます。

75
mirk

末尾の戻り型を使用する必要がある特定のケースがあります。最も顕著なのは、ラムダ戻り値の型が指定されている場合、末尾の戻り値の型を介して指定する必要があることです。また、戻り値の型がdecltypeを使用する場合、引数名がスコープ内にある必要があるため、末尾の戻り値の型を使用する必要があります(ただし、通常はこの後者の問題を回避するためにdeclval<T>を使用できます) 。

末尾の戻り型には、他にもいくつかの小さな利点があります。たとえば、従来の関数構文を使用した非インラインメンバー関数の定義を考えます。

struct my_awesome_type
{
    typedef std::vector<int> integer_sequence;

    integer_sequence get_integers() const;
}; 

my_awesome_type::integer_sequence my_awesome_type::get_integers() const
{
    // ...
}

メンバのtypedefは、クラス名が::get_integersの前に現れるまでスコープ内にないため、クラス修飾を2回繰り返す必要があります。末尾の戻り型を使用する場合、型の名前を繰り返す必要はありません。

auto my_awesome_type::get_integers() const -> integer_sequence
{
    // ...
}

この例では、それほど大きな問題ではありませんが、インラインで定義されていない長いクラス名またはクラステンプレートのメンバー関数がある場合、読みやすさに大きな違いが生じる可能性があります。

Alisdair Meredithは、C++ Now 2012での彼の "Fresh Paint" セッションで、後続の戻り値型を一貫して使用すると、すべての関数の名前がきちんと並んでいると指摘しました。

auto foo() -> int;
auto bar() -> really_long_typedef_name;

CxxReflect のすべての場所で末尾の戻り値の型を使用しているので、コードを一貫して使用するコードの例を探している場合は、そこを調べることができます(たとえば the type class )。

88
James McNellis

他の人が言ったことに加えて、末尾の戻り値の型では、thisを使用することもできます。

_struct A {
  std::vector<int> a;

  // OK, works as expected
  auto begin() const -> decltype(a.begin()) { return a.begin(); }

  // FAIL, does not work: "decltype(a.end())" will be "iterator", but 
  // the return statement returns "const_iterator"
  decltype(a.end()) end() const { return a.end(); }
};
_

2番目の宣言では、従来のスタイルを使用しました。ただし、thisはその位置では許可されないため、コンパイラは暗黙的に使用しません。したがって、a.end()は、静的に宣言されたaの型を使用して、_vector<int>_のどのendオーバーロードを呼び出すかを決定します。 。

もう1つの利点は、関数が関数へのポインターを返すときに、末尾戻り型の構文が読みやすくなることです。たとえば、比較

void (*get_func_on(int i))(int);

auto get_func_on(int i) -> void (*)(int);

ただし、関数ポインタに型エイリアスを導入するだけで、読みやすくなると主張できます。

using FuncPtr = void (*)(int);
FuncPtr get_func_on(int i);
18
s3rvac

この素敵な記事を参照してください: http://www.cprogramming.com/c++11/c++11-auto-decltype-return-value-after-function.html 非常に良い例ゲームでdecltypeを使用せずにこの構文を使用します。

class Person
{
public:
    enum PersonType { ADULT, CHILD, SENIOR };
    void setPersonType (PersonType person_type);
    PersonType getPersonType ();
private:
    PersonType _person_type;
};

auto Person::getPersonType () -> PersonType
{
    return _person_type;
}

また、Alex Allainの記事「戻り値は関数の前ではなく最後にあるため、クラススコープを追加する必要はありません」からも素晴らしい説明が盗まれました。

偶然にクラスのスコープを忘れてしまい、より大きな災害のために別のPersonTypeがグローバルスコープで定義されているこの可能性のあるケースと比較してください。

typedef float PersonType; // just for even more trouble
/*missing: Person::*/
PersonType Person::getPersonType ()
{
    return _person_type;
}
8
PiotrNycz