2013-05-26 12 views
15

Co dzieje się w tym kodzie? Jest taki mylący.Co oznacza -> po prototypie funkcji?

#include <utility> 

struct check 
{ 
    template <typename T> 
    auto foo() -> decltype(std::declval<T>().value, void()) 
    { 
     static_assert(T{}.value == 10, "Incorrect value"); 
    } 
} var; 

int main() 
{ 
    struct apple 
    { 
     int value{10}; 
    }; 

    var.foo<apple>(); 
} 

W szczególności część, w której znajduje się -> i wszystko inne.

+2

The -> to końcowy typ powrotu. 'declval' tworzy instancję klasy. 'decltype' znajduje typ wyrażenia podczas kompilacji. 'static_assert' jest asemblowaniem podczas kompilacji. Czas połączyć je w całość :) – chris

+3

Niejasny tytuł nie przyda się innym osobom z tym samym pytaniem. –

+1

@RiaD: Chociaż edycja tytułu jest bardziej pomocna, wciąż jest niedokładna - wydaje się, że pyta o konkretne użycie. –

Odpowiedz

10

Przejdźmy krok po kroku.

auto foo() -> decltype(std::declval<T>().value, void()) 

Jest to końcowy typ powrotu. Można używać parametrów, ale tutaj nie jest to konieczne. Domyślam się, że napisano tak, żeby było wyraźniej. decltype znajduje typ wyrażenia w środku, ale to wyrażenie nie jest w rzeczywistości obliczane. std::declval służy do tworzenia instancji typu przekazanego do niej. Operator przecinka służy tutaj do generowania ogólnego zwrotu typu void, ponieważ operator przecinka ocenia lewą stronę, odrzuca ją, ocenia prawą stronę i zwraca ją.

Pierwsza część tworzy rodzaj SFINAE (chociaż nigdy nie widziałem, żeby była używana w ten sposób). Na przykład, jeśli masz przeciążenie foo, które zrobiło to samo z value2 zamiast , nie byłoby żadnej niejednoznaczności do wywołania. Zobacz here o co mi chodzi. Porównaj go z this one, który ma tylko typ zwrotu void i powoduje błędy.

static_assert(T{}.value == 10, "Incorrect value"); 

Linia ta pilnuje instancja wartości zainicjowany z T został członkiem jego value mieć wartość 10. Jeśli nie, to błąd kompilatora z tego tekstu jest generowany.

} var; 

To jest tylko globalny obiekt tej klasy do użycia.

struct apple 
{ 
    int value{10}; 
}; 

To jest klasa próbki do przetestowania. Ma element value i ten element ma wartość 10 w instancji inicjowanej wartością (również inicjowana domyślnie).

var.foo<apple>(); 

To po prostu wywołuje funkcję.

+0

Kiedy robię "struct grape {}; var.foo (); 'daje mi błąd. Jak mogę sprawić, że będzie po cichu zawieść? –

+0

@MemyselfandI, Musisz mieć wersję 'foo', która działa na strukturach takich jak winogrona. Chodzi o to, że musisz się upewnić, że wywołanie go z 'apple' nie jest niejednoznaczne. Spróbuję przygotować przykład. – chris

+0

@MemyselfandI, Wielkie dzięki dla Xeo, [proszę) (http://coliru.stacked-crooked.com/view?id=200ce7dd4c270d3bfdea6df8628f6e4e-8a676986784bd3a58ce3ec015645a41f). To jest miejsce, w którym można zaimplementować 'foo' w zależności od tego, czy typ ma element danych o wartości' value' czy nie. – chris