戻り値の型を明示的に述べているにもかかわらず、ラムダの呼び出しがあいまいです


11

オーバーロードされた関数は、ラムダのタイプが決定可能であることを前提に、両方のファンクターを取り込む必要があります(キャスト可能(std::function私が間違っている場合は修正してください)。定義されていますか?([&]() -> Type {}

現在のソリューションでは、参照によるキャプチャが必要なため、コードにそのロジックが含まれていることに注意してください。

次の例は、問題について説明しています。

#include <iostream>
#include <string>    
#include <functional>

void do_some(std::function<void(int)> thing) 
{
   thing(5);
}

void do_some(std::function<bool(int)> thing)
{
   if (thing(10)) 
   {
      std::cout << "it's true!" << std::endl;
   }
}

int main()
{
   int local_to_be_modified = 0;
   do_some(
      [&](int in)
      {
         local_to_be_modified = in;
         std::cout << "This is void-" << std::endl;
      }
   );
   do_some(
      [&](int in) -> bool
      { 
         // error: call to 'do_some' is ambiguous
         local_to_be_modified += in;
         std::cout << "This is bool-" << std::endl;
         return true;
      }
   );
}

6
std::function<void(int)>何かを返すラムダからでも構築できるため(戻り値は無視されます)。
HolyBlackCat

1
余談ですが、そのラムダの戻り値の型を明示的に指定しても、まったく何も起こりません。
Deduplicator

回答:


8

なぜなら、返される2番目のラムダ式boolstd::function<void(int)>std::function<bool(int)>暗黙的にも両方にも変換できるからです。

std::function 変換コンストラクタがあります:

template< class F >
function( F f );

このコンストラクタは、fが引数型Args ...でCallableで、型Rを返さない限り、オーバーロードの解決に参加しません。(C ++ 14以降)

Callableの定義として、

次の式が有効である必要があります。

INVOKE<R>(f, std::declval<ArgTypes>()...)

ここで、INVOKE(f、t1、t2、...、tN)static_cast<void>(INVOKE(f, t1, t2, ..., tN))、Rがおそらくcv修飾されているかのように定義され void、それ以外の場合はINVOKE(f、t1、t2、...、tN)が暗黙的にRに変換されます

上記のようにbool、に対してを返す2番目のラムダは有効な式であることに注意してください(返される値は単にに変換されます)。次に、暗黙的に変換され、あいまいさの問題が発生する可能性があります。std::function<void(int)>static_cast<void>(INVOKE(f, t1, t2, ..., tN))boolvoidstd::function<void(int)>


6

static_castラムダを適切な型に明示的に指定できます

using FunBoolRet = std::function<bool(int)>;

do_some(static_cast<FunBoolRet >([&](int in) 
   {
      local_to_be_modified += in;
      std::cout << "This is bool-" << std::endl;
      return true;
   }));

または、ラムダを適切なstd::function<bool(int)>タイプに保存して関数に渡します(do_some(lmda)何度も呼び出す必要がある場合)

FunBoolRet lmda = [&](int in)
{
    local_to_be_modified += in;
    std::cout << "This is bool-" << std::endl;
    return true;
};    
do_some(lmda); // pass the lambda

または、@ MaxLanghofが 提案std::function<bool(int)>するように、外出先でラムダから単に構築する

do_some(FunBoolRet{
   [&](int in) 
   {
      local_to_be_modified += in;
      std::cout << "This is bool-" << std::endl;
      return true;
   }
});

をスキップしてstatic_caststd::functionそこから直接を作成できます。とにかく、暗黙の変換中にそれがすべてです。
Max Langhof

私のポイントは、あなたが文字通り取り除くことができるということですstatic_cast<し、最後に>、それはあまりタイピングと同じことを行います。それ以上の行などは必要ありません。godbolt.org/z/fQTqF4
Max
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.