2014-09-10 10 views
14

Chcę sprawdzić, czy istnieje funkcja nie-element członkowska akceptująca typ parametru T. W tym celu użyłem "sztuczki" void_t przedstawionej przez pana Waltera E. Browna w cppcon (ta sama sztuczka działa bez żadnych problemów, aby sprawdzić, czy istnieje typ członka lub funkcja członka).Sprawdzanie, czy istnieje funkcja nie-składowa akceptująca T param

#include <iostream> 
#include <type_traits> 

template<typename...> 
using void_t = void; 

void Serialize(float&) 
{ 
} 

template<typename T, typename = void> 
struct has_external_serialize : std::false_type 
{ 
}; 

template<typename T> 
struct has_external_serialize<T, void_t<decltype(Serialize(std::declval<T&>()))>> : std::true_type 
{ 
}; 

void Serialize(int&) 
{ 
} 

int main(int argc, const char * argv[]) 
{ 
    std::cout<<has_external_serialize<float>::value<<has_external_serialize<int>::value; 
} 

Kod ten drukuje 11 gdy tworzone przy użyciu gcc 10 kiedy zestawiane z brzękiem xcode (5.1.1).

Moje pytania to - czy ten kod jest prawidłowy? Jeśli tak, czy jest jakiś błąd w klangu lub błąd w GCC, czy kod znajduje się w jakimś "zdefiniowanym przez implementację" obszarze i nie mogę założyć, że będzie to samo zachowanie na wszystkich platformach?

+0

Typy zależne od pendrive oraz typy "std" przed specjalizacją. Inne typy używają ADL. Wtedy klang będzie szczęśliwy.Wierzę, że to, co zrobiłeś, jest źle sformułowane, ale nie masz czasu, aby to udowodnić. – Yakk

+3

Wygląda bardziej jak błąd w GCC (przynajmniej 4.9.0), ponieważ wypisuje '11' nawet dla' struct has_external_serialize ())) >>: std :: true_type' –

+1

@Felics: Witamy w CppCon! :-) –

Odpowiedz

4

Rozbieżność między kompilatorów jest spowodowane definicji void_t: Is there a compiler bug exposed by my implementation of an is_complete type trait? Krótko mówiąc, średnia było jasne, czy niewykorzystane argumenty alias specjalizacji szablonu może spowodować niewydolność substytucyjnego lub są po prostu ignorowane. W rezolucji do CWG issue 1558 wyjaśniono, że krótsza definicja void_t w pytaniu powinna działać.

Z tej kwestii obejść stosując

template<typename... Ts> 
struct make_void { typedef void type;}; 

template<typename... Ts> 
using void_t = typename make_void<Ts...>::type; 

both compilers produce 10.

§14.6.4.2 [temp.dep.candidate]:

Dla wywołania funkcji, która zależy od parametru szablonu, funkcje kandydujące znajdują stosując zwyczajowe zasady odnośników (3.4.1, 3.4.2, 3.4.3), z wyjątkiem, że:

  • Dla części odnośnika przy użyciu nazwy bez zastrzeżeń odnośnika (3.4.1) lub nazwa kwalifikowana odnośnika (3.4.3) tylko deklaracje funkcji z definicji szablonu kontekst znajduje się.
  • Dla części wyszukiwania przy użyciu powiązanych przestrzeni nazw (3.4.2), znaleziono tylko deklaracje funkcji znajdujące się w kontekście definicji szablonu lub kontekście tworzenia instancji szablonu.

Jeżeli nazwa funkcji jest niewykwalifikowany-id a rozmowa będzie źle sformułowane lub byłoby znaleźć lepszy mecz miał odnośnika obrębie związanych nazw rozpatrzył wszystkie deklaracje funkcji z powiązania zewnętrznego wprowadzonego w tych przestrzeniach nazw we wszystkich jednostkach tłumaczeniowych , nie tylko biorąc pod uwagę deklaracje znajdujące się w szablonie definicji instancji i szablonu, program ma niezdefiniowane zachowanie.

Nieuwarunkowany odnośnika do Serialize odbywa się w kontekście definicji szablonu i nie znajdzie Serialize(int &), i nie ma ADL dla argumentu typu int&, więc 10 jest prawidłowe wyjście.

Powiązane problemy