2015-01-03 16 views
10

Rozważmy następujący przykładprzeciążenie Funkcja użyciu lambda funkcja podpis

void foo(const std::function<int()>& f) { 
    std::cout << f() << std::endl; 
} 

void foo(const std::function<int(int x)>& f) { 
std::cout << f(5) << std::endl; 
} 

int main() { 
    foo([](){return 3;}); 

    foo([](int x){return x;}); 
} 

nie skompilować, ponieważ wywołanie foo mówi się niejednoznaczna. O ile rozumiem, wynika to z faktu, że funkcja lambda nie jest a priori a std::function, ale musi zostać do niej rzucona i że istnieje konstruktor std::function, który przyjmuje dowolny argument.

Może ktoś może mi wyjaśnić, dlaczego ktoś utworzył niejawny konstruktor, który bierze arbitralny argument. Jednak moje jednoznaczne pytanie dotyczy tego, czy istnieje obejście, które umożliwia wykorzystanie funkcji sygnatury funkcji lambda do przeciążenia funkcji foo. Próbowałem wskaźników funkcji, ale to nie działało, ponieważ przechwytywanie funkcji lambda nie może być rzutowane na normalny wskaźnik funkcji.

Każda pomoc jest mile widziana.

+7

To prawdopodobnie błąd w MSVC. Działa w Clang/GCC. –

+2

O Microsoft, jesteś taki zabawny –

+0

[Działa dla mnie] (http://ideone.com/XmAgLG). Który kompilator używasz? –

Odpowiedz

15

Twój kompilator jest poprawny zgodnie z C++ 11. W C++ 14 dodano regułę, która mówi, że szablon konstruktora nie będzie uczestniczył w rozwiązywaniu przeciążenia, chyba że typ argumentu jest rzeczywiście możliwy do wywołania z argumentami typu std::function. Dlatego ten kod powinien być skompilowany w C++ 14, ale nie w C++ 11. Rozważmy to jako niedopatrzenie w C++ 11.

Na razie można to obejść przez wyraźnej konwersji:

foo(std::function<int()>([](){return 3;})); 
+0

Dzięki za wyjaśnienia. Po komentarzach próbowałem go używając GCC 4.8 (i '-std = C++ 11') i działało. Jakoś zabawne, że nowsza wersja GCC nie używa zatem ściśle poprawnego C++ 11. – Haatschii

+1

@Haatschii Jest to defekt w standardzie C++ 11; twórcy kompilatora/biblioteki zwykle stosują poprawki z mocą wsteczną.(Poza tym był to UB w C++ 11, tak więc zachowanie C++ 14 jest dopuszczalne.) –

4

http://coliru.stacked-crooked.com/a/26bd4c7e9b88bbd0

alternatywą do korzystania z std :: funkcja jest użycie szablonów. Szablony zapobiegają obciążeniu pamięci związanym z funkcją std ::. Mechanizm dedukcji typu szablonu wyprowadzi prawidłowy typ lambda, aby odrzucić obsadę strony wywoławczej. Nadal masz jednak ujednoznacznić przeciążenia dla przypadku no-args vs args.

Możesz to zrobić za pomocą sztuczki z końcowymi typami zwracania, które zachowują się podobnie do enable_if.

template<typename Callable> 
auto baz(Callable c) 
    -> decltype(c(5), void()) 
{ 
    std::cout << c(5) << std::endl; 
} 

Powyższy przeciążenie baz będzie tylko ważne kandydat przeciążenie gdy parametr szablonu Callable może być wywołana z argumentem 5.

można umieścić bardziej zaawansowane mechanizmy na szczycie tego uczynić go bardziej ogólna (tj. rozszerzenie paczek variadic argumentów na wywoływalne), ale chciałem pokazać działanie podstawowego mechanizmu.

Powiązane problemy