5

提供されたラムダを呼び出す関数を提供しようとしていますが、関数の戻り値がタイプの場合、デフォルト値を返すことができるかどうか疑問に思っていますvoid

これが私がこれまでに持っているものです。ラムダの戻り値を返す関数ですが、ラムダがの場合、void20を返します。

#include <functional>
#include <iostream>

template <typename H>
auto f(H&& h) -> decltype(h(), void())
{
    return h();
}

template <typename H>
auto f(H&& h) -> decltype(h(), int())
{
    h();
    return 20;
}

int main()
{
    int r = f([](){ std::cout << "test1" << std::endl; return 10; }); // error here
    std::cout << "r: " << r << std::endl;
    r = f([](){ std::cout << "test2" << std::endl; });
    std::cout << "r: " << r << std::endl;

    return 0;
}

これにより、エラーが発生します。

test.cpp:20:68: error: call of overloaded ‘f(main()::<lambda()>)’ is ambiguous

したがって、これは明らかに、C++が戻り型に基づくポリモーフィズムを使用できないためです。decltypeただし、これを可能にする可能性のある、C ++ 11の優れたトリック(テンプレートの魔法の使用法やテンプレートの魔法など)があるかどうか疑問に思っています。私が見る限り、ここには本当のあいまいさはないので、私は尋ねています。コンパイラは戻り型を推測し、またはのバージョンvoidと一致するかどうかがあいまいであると言っています。これは少しばかげています。intvoidf

これを行う理由は、関数fが戻り値を期待しているが、ユーザーがステートメントを含まないラムダを提供した場合return、コンパイラーがvoid型を推測し、エラーになるためです。実際のシナリオでは、ユーザーがデフォルトの戻り値を提供する必要がない場合に、適切なデフォルトの戻り値がどうあるべきかをよく理解しているので、コンパイラーでユーザーが頻繁に不要なreturnステートメントを無視できるようにすることができるかどうか疑問に思います。快適。

ありがとう。私はGCC4.6.3を使用していることに言及する必要があります。

回答:Xeoの使用の提案に基づいてenable_if、私は次のことを思いつきました。これは機能しているようです。

template <typename H>
auto f(H&& h) -> typename std::enable_if<std::is_same<decltype(h()), void>::value, int>::type
{
    h();
    return 20;
}

template <typename H>
auto f(H&& h) -> typename std::enable_if<std::is_same<decltype(h()), int>::value, int>::type
{
    return h();
}

ありがとう!

4

2 に答える 2

3

std::enable_if を使用できます。

戻り値の型はstd::enable_if<!std::is_same<decltype(h()), void>::value, decltype(h())>:type、最初のものとstd::enable_if<std::is_same<decltype(h()), void>::value, int>::type2 番目のものになります。これでコードが機能するはずです。私はそれをテストしていないので、完全に機能するかどうかはわかりません。

于 2012-09-22T19:45:57.680 に答える
2

関数内で何をするかに基づいて、コンパイラがどのオーバーロードを選択するのかを推測できる理由を教えてください。C ++では、オーバーロードの解決は、すべての引数がパラメーターに一致する場合にのみ関係します。戻り値のタイプと関数の内容は、まったく関係ありませ

STLが言うように

TLDR:テンプレートは貪欲です!何が起こるか絶対に確信が持てない限り、それらをオーバーロードしないでください。

template<class T> void f(T&&);そして、パラメータとしてのユニバーサルリファレンス( )は、あなたが得ることができる最も貪欲です。

@JKorがSFINAEで言うように解決できますが、単純化されています。

#include <type_traits>

template<class F>
auto f(F f)
  -> decltype(true? f() : void())
{
  f();
}

template <class F>
auto f(F f) -> decltype(int(f()))
{
  f();
  return 42;
}

int main(){
  f([]{});
}

GCC 4.7にはdecltype(int(void_returning_function()))、関数がSFINAEを実行しないバグがあることに注意してください。Clang3.1は正しく

f([]{});

仕事だけでなく

f([]{ return 42; });
于 2012-09-22T21:17:57.050 に答える