2017-12-18 3 views
2

Ich bin interessiert zu verstehen, welche Arten von Vorlagen als das erste Argument von std::experimental::is_detected und ähnliche Erkennungsdienstprogramme verwendet werden können.Welche Arten von Vorlagen können mit is_detected verwendet werden?

Unten ist eine Implementierung von is_detected eingefügt und ein Versuch, es zu verwenden, um zu erkennen, ob ein Typ T eine Mitgliedsfunktion hat, die .foo() benannt wird. Das allgemeine Muster verwendet es ist, zuerst einen Typ Merkmal zu definieren, die den Typ einer Elementfunktion zurückgibt T::foo, wenn es vorhanden ist:

template<class T> 
struct member_foo_result 
{ 
    using type = decltype(std::declval<T>().foo()); 
}; 

Dann legt er eine Kurz alias:

template<class T> 
using member_foo_result_t = typename member_foo_result<T>::type; 

Das Problem ist, dass der Stenogramm-Alias ​​mit inkompatibel zu sein scheint.

Hier ist das vollständige Programm, mit Compiler Ausgabe:

#include <utility> 
#include <type_traits> 
#include <iostream> 

// implementation of is_detected 
template<class...> 
using void_t = void; 

struct nonesuch 
{ 
    nonesuch() = delete; 
    ~nonesuch() = delete; 
    nonesuch(const nonesuch&) = delete; 
    void operator=(const nonesuch&) = delete; 
}; 


template<class Default, class AlwaysVoid, 
     template<class...> class Op, class... Args> 
struct detector 
{ 
    using value_t = std::false_type; 
    using type = Default; 
}; 


template<class Default, template<class...> class Op, class... Args> 
struct detector<Default, void_t<Op<Args...>>, Op, Args...> 
{ 
    using value_t = std::true_type; 
    using type = Op<Args...>; 
}; 
template<template<class...> class Op, class... Args> 
using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t; 



// returns the result type of T::foo() 
template<class T> 
struct member_foo_result 
{ 
    using type = decltype(std::declval<T>().foo()); 
}; 

// shorthand alias for member_foo_result<T>::type 
template<class T> 
using member_foo_result_t = typename member_foo_result<T>::type; 


// detects whether or not the member function T::foo() exists 
template<class T> 
struct has_foo_member : is_detected<member_foo_result_t, T> {}; 


struct doesnt_have_foo_member {}; 


int main() 
{ 
    std::cout << "result: " << has_foo_member<doesnt_have_foo_member>::value << std::endl; 
} 

ich dieses Programm erwarten drucken "Ergebnis: 0" zur Laufzeit. Allerdings ist kompilieren es nicht richtig:

$ clang -std=c++11 test_is_detected.cpp 
test_is_detected.cpp:41:43: error: no member named 'foo' in 'doesnt_have_foo_member' 
    using type = decltype(std::declval<T>().foo()); 
         ~~~~~~~~~~~~~~~~~^
test_is_detected.cpp:45:1: note: in instantiation of template class 'member_foo_result<doesnt_have_foo_member>' requested here 
using member_foo_result_t = typename member_foo_result<T>::type; 
^ 
test_is_detected.cpp:27:33: note: in instantiation of template type alias 'member_foo_result_t' requested here 
struct detector<Default, void_t<Op<Args...>>, Op, Args...> 
           ^
test_is_detected.cpp:33:1: note: during template argument deduction for class template partial specialization 'detector<type-parameter-0-0, void, Op, type-parameter-0-2...>' [with Default = nonesuch, Op = 
     member_foo_result_t, Args = <doesnt_have_foo_member>] 
using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t; 
^ 
test_is_detected.cpp:50:25: note: in instantiation of template type alias 'is_detected' requested here 
struct has_foo_member : is_detected<member_foo_result_t, T> {}; 
         ^
test_is_detected.cpp:58:30: note: in instantiation of template class 'has_foo_member<doesnt_have_foo_member>' requested here 
    std::cout << "result: " << has_foo_member<doesnt_have_foo_member>::value << std::endl; 
          ^
1 error generated. 

Bin ich is_detected mißbrauchen?

Antwort

4

is_detected ist für die Verwendung mit Alias-Vorlagen vorgesehen, die bei der Instanziierung mit "falschen" Argumenten einen Fehler im unmittelbaren Kontext (d. H. SFINAE-freundlich) verursachen.

Das bedeutet, dass die Substitution Fehler erkannt werden muss, um in der Alias-Vorlage selbst auftreten, anstatt einig Klassenvorlage es instanziiert:

template<class T> 
using member_foo_result_t = decltype(std::declval<T>().foo()); 
Verwandte Themen