Dönüş türünü açıkça belirtmesine rağmen lambda'ya çağrı belirsiz


11

Aşırı yüklenmiş bir fonksiyon, lambda türünün karar verilebilir olması durumunda std::function( her ikisini de almalı (bir yanıltıcı olursam lütfen beni düzeltin)) Her iki işlevi de almalıdır . tanımlandı? ( [&]() -> Type {})

Mevcut çözümüm için referans yakalamaya ihtiyacım olduğunu, kodun bunun için mantığı içerdiğini lütfen unutmayın.

Aşağıdaki örnekte sorun açıklanmaktadır:

#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
Çünkü std::function<void(int)>bir şey döndüren bir lambdadan bile yapılabilir (bu, dönüş değerinin göz ardı edilmesine neden olur).
HolyBlackCat

1
Bir yana, bu lambda'nın dönüş tipini açıkça belirtmek hiçbir şey yapmıyor.
Tekilleştirici

Yanıtlar:


8

2 lambda ifadesi dönen Çünkü boolhem dönüştürmek olabilir std::function<void(int)>ve std::function<bool(int)>dolaylı.

std::function bir dönüştürücü kurucuya sahiptir:

template< class F >
function( F f );

Bu yapıcı f olmadıkça aşırı yük çözünürlükte katılmaz çağrılabilir bağımsız değişken türleri Args için ... ve döndürme türü R. (beri C ++ 14)

Callable'ın tanımı olarak ,

Aşağıdaki ifadeler geçerli olmalıdır:

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

burada INVOKE (f, T1, T2, ..., Tn) gibi tanımlanmıştır static_cast<void>(INVOKE(f, t1, t2, ..., tN))R, muhtemelen ev nitelikli ise void, aksi halde, INVOKE (f, T1, T2, ..., Tn) , dolaylı olarak R dönüştürüldü

2. lambda geri bu Not booliçin, std::function<void(int)>yukarıda gösterildiği gibi, static_cast<void>(INVOKE(f, t1, t2, ..., tN))geçerli bir ekspresyon (döndürülen olduğu boolgibi dönüştürülür void). Sonra da std::function<void(int)>örtük olarak dönüşebilir ve belirsizlik sorununa neden olabilir .


6

static_castLambda'yı açıkça uygun türe yapabilirsiniz

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;
   }));

Veya lambda'yı uygun std::function<bool(int)>tipte saklayın ve işleve geçin (eğer do_some(lmda)birçok kez çağrılmalıdır)

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

Ya da @MaxLanghof'un önerdiği gibi hareket halindeyken lambda'dan inşa std::function<bool(int)>edin

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

Atlayabilir static_castve std::functiondoğrudan ondan bir yapı oluşturabilirsiniz . Zaten örtük dönüşüm sırasında olan her şey budur.
Max Langhof

Demek istediğim, kelimenin tam anlamıyla static_cast<ve sonunu kaldırabilirsiniz ve >aynı şeyi daha az yazarak yapacak. Daha fazla çizgiye veya başka bir şeye ihtiyacı yoktur. godbolt.org/z/fQTqF4
Max Langhof
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.