web-dev-qa-db-ja.com

関数の戻り値の型を決定する最も簡単な方法

次のような非常に単純だが長い関数を与えられた場合:

int foo(int a, int b, int c, int d) {
    return 1;
}

// using ReturnTypeOfFoo = ???

コンパイル時に関数の戻り値の型(ReturnTypeOfFoo、この例ではint)を決定する最も簡単で簡潔な方法は何ですか関数のパラメーター型を繰り返さずに(名前による)のみ、関数に追加のオーバーロードがないことがわかっているため)

47
Cybran

std::function を活用して、関数の戻り型のtypedefを取得できます。 クラステンプレート引数の推論 に依存しているため、これにはC++ 17のサポートが必要ですが、呼び出し可能なすべての型で機能します。

using ReturnTypeOfFoo = decltype(std::function{foo})::result_type;

これをもう少し一般的にすることができます

template<typename Callable>
using return_type_of_t = 
    typename decltype(std::function{std::declval<Callable>()})::result_type;

その後、次のように使用できます

int foo(int a, int b, int c, int d) {
    return 1;
}

auto bar = [](){ return 1; };

struct baz_ 
{ 
    double operator()(){ return 0; } 
} baz;

using ReturnTypeOfFoo = return_type_of_t<decltype(foo)>;
using ReturnTypeOfBar = return_type_of_t<decltype(bar)>;
using ReturnTypeOfBaz = return_type_of_t<decltype(baz)>;
54
NathanOliver

最も単純で簡潔なものはおそらく次のとおりです。

template <typename R, typename... Args>
R return_type_of(R(*)(Args...));

using ReturnTypeOfFoo = decltype(return_type_of(foo));

これは、関数オブジェクトまたはメンバー関数へのポインターでは機能しないことに注意してください。オーバーロードされていない関数、テンプレート、またはnoexcept

ただし、必要に応じて、return_type_ofのオーバーロードを追加することで、これらのすべてのケースをサポートするように拡張できます。

22
Barry

私が最も簡単な方法であるかどうかはわかりません(C++ 17を使用できる場合はそうではありません:NathanOliverの答えを参照してください)が...次のように関数を宣言するのはどうですか:

template <typename R, typename ... Args>
R getRetType (R(*)(Args...));

decltype()?を使用していますか?

using ReturnTypeOfFoo = decltype( getRetType(&foo) );

getRetType()decltype()のみと呼ばれるため、宣言されるだけで定義されないことに注意してください。したがって、返される型のみが関連します。

15
max66