2012-08-17 20 views
15

Chciałbym napisać funkcję szablonu, która akceptuje 2 wartości i funktora lub lambda. Funkcja wywołuje funktor z tymi wartościami i zwraca wynik.Jak wywnioskować typ wartości zwracanej przez funktor?

template <typename T, typename Fn> 
_ReturnTypeOfPred_ Apply(T x, T y, Fn fn) 
    { 
    return fn(x, y); 
    } 

Pytanie: W jaki sposób można określić typ zwracanej Apply stać równa typu zwracanej Fn? To niekoniecznie jest równa T, jak w tym przykładzie funktora

template <typename T> 
auto Sum(T x, T y) -> decltype(x+y) 
    { 
    return x+y; 
    } 

aktualizacji

The 1st przykład został uproszczony. Czy to powinno zadziałać?

template <typename TContainer, typename Fn> 
auto Apply(const TContainer& x, const TContainer& y, Fn fn) -> decltype(fn(x.front(), y.front())) 
    { 
    return fn(x.front(), y.front()); 
    } 

Czy to zawsze działa, jeśli powtarzam return wyraz w decltype zwracanego typu? Czy istnieje bardziej elegancki sposób?

+2

Podkreślone nazwy kapitału są zarezerwowane dla implementacji. Nie wolno ich używać we własnym kodzie. –

+2

@KerrekSB: To był symbol zastępczy, a nie prawdziwy kod – Andrey

+0

Dobre funktory (takie jak te w STL) zawsze definiują ich 'return_type', więc możesz po prostu użyć' Fn :: return_type'. Ale rozumiem, że chcesz odpowiedzi, która działa również dla niezbyt dobrych funktorów. – Gorpik

Odpowiedz

18

Już prawie jesteś; wystarczy użyć decltype:

template <typename T, typename Fn> 
auto Apply(T x, T y, Fn fn) -> decltype(fn(x, y)) 
{ 
    return fn(x, y); 
} 

Można użyć std::result_of (Difference between std::result_of and decltype), ale po co się męczyć?

template <typename T, typename Fn> 
typename std::result_of<Fn, T, T>::type Apply(T x, T y, Fn fn) 
{ 
    return fn(x, y); 
} 

Jeśli chodzi o kolejne pytanie: dla funkcji

auto fn(<args>) -> <return-type> { return <expression>; } 

zastępując return-type z decltype(<expression>) będzie zwykle pracy, ale mogą być podatne na błędy. Rozważmy na przykład:

auto f(char c) -> decltype(std::string() += c) { return std::string() += c; } 

Tutaj decltype przyniesie std::string & a funkcja zwróci lwartością odniesienie do lokalnej! To musi być zmienione na:

auto f(char c) -> std::remove_reference<decltype(std::string() += c)>::type { 
    return std::string() += c; 
} 

w innych przypadkach, może przynieść <expression> wartość, która nie jest zwracany na przykład w związku z czym niekopiąca się, zawierająca lambda itd.

+0

Dziękuję. Czy mógłbyś rzucić okiem na zaktualizowane pytanie? – Andrey

+0

@Andrey patrz wyżej. – ecatmur

+0

Złożone przez ciebie pytanie nie bardzo dobrze podkreśla różnice między 'std :: result_of' i' decltype'. Na potrzeby PO "std :: result_of" nie jest właściwe. –

Powiązane problemy