2016-07-23 21 views
1
#include <vector> 
#include <iostream> 
#include <type_traits> 

using namespace std; 

template<typename Coll> 
class has_push_back 
{ 
    using coll_type = decay_t<Coll>; 
    using True = char(&)[1]; 
    using False = char(&)[2]; 

    template<typename U, void(U::*)(const typename U::value_type&)> 
    struct SFINAE {}; 

    template<typename T> 
    static True Test(SFINAE<T, &T::push_back>*); 

    template<typename T> 
    static False Test(...); 

public: 
    enum { value = sizeof(Test<coll_type>(nullptr)) == sizeof(True) }; 
}; 

class MyColl : public vector<int> {}; 

int main() 
{ 
    cout << has_push_back<vector<int>>::value << endl; 
    cout << has_push_back<MyColl>::value << endl; 
} 

Das Programm oben AUSGABE:Wie überprüft man, ob eine Klasse eine geerbte Funktion zur Kompilierzeit hat?

1 
0 

Es zeigt die Vorlage has_push_back funktioniert nicht, wenn die Funktion push_back vererbt wird.

Gibt es eine Möglichkeit, es zu funktionieren, auch wenn es geerbt ist?

Antwort

1

Aus Gründen der Vollständigkeit, würde Ich mag einen anderen Ansatz bisher nicht erwähnt posten.
Dies basiert auf den Definitionen der Funktionen und einer Alias-Deklaration.
Es folgt ein minimales, funktionierendes Beispiel:

#include <vector> 
#include <type_traits> 
#include<utility> 

using namespace std; 

template<typename T, typename... U> 
constexpr auto f(int) 
-> std::conditional_t<false, decltype(std::declval<T>().push_back(std::declval<U>()...)), std::true_type>; 

template<typename, typename...> 
constexpr std::false_type f(char); 

template<typename T, typename... U> 
using has_push_back = decltype(f<T, U...>(0)); 

class MyColl : public vector<int> {}; 

int main() { 
    static_assert(has_push_back<vector<int>, int>::value, "!"); 
    static_assert(has_push_back<MyColl, int>::value, "!"); 
} 
1

Nach this Antwort könnte Ihr Code wie folgt aussehen:

#include <type_traits> 

// Primary template with a static assertion 
// for a meaningful error message 
// if it ever gets instantiated. 
// We could leave it undefined if we didn't care. 

template<typename, typename T> 
struct has_push_back { 
    static_assert(
     std::integral_constant<T, false>::value, 
     "Second template parameter needs to be of function type."); 
}; 

// specialization that does the checking 

template<typename C, typename Ret, typename... Args> 
struct has_push_back<C, Ret(Args...)> { 
private: 
    template<typename T> 
    static constexpr auto check(T*) 
    -> typename 
     std::is_same< 
      decltype(std::declval<T>().push_back(std::declval<Args>()...)), 
      Ret // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
     >::type; // attempt to call it and see if the return type is correct 

    template<typename> 
    static constexpr std::false_type check(...); 

    typedef decltype(check<C>(0)) type; 

public: 
    static constexpr bool value = type::value; 
}; 

Alle Gutschriften

@jork Sie wahrscheinlich Code aus this Antwort verwendet habe, aber es ist nicht mit geerbten Funktionen arbeiten .

2

Hier a solutionvoid_t verwenden, die in C++ 17-Standard und kommt auch mit zusätzlichen Dienstprogramme wie is_detected_exact in der Bibliothek Fundamentals v2 TS, die meiste Arbeit aus has_push_back unter:

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

template<typename T> 
using push_back_test = decltype(std::declval<T>().push_back(std::declval<typename T::const_reference>())); 

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

template<typename T> 
struct has_push_back<T, void_t<push_back_test<T>>> : std::is_same<push_back_test<T>, void> {}; 

Or with future utilities:

template<typename T> 
using push_back_test = decltype(std::declval<T>().push_back(std::declval<typename T::const_reference>())); 

template<typename T> 
using has_push_back = std::experimental::is_detected_exact<void, push_back_test, T>; 

Wenn Sie void_t im Detail erfahren möchten, schlage ich vor, die Überprüfung Walter Brown's CppCon 2015 talks aus.

2
template<typename Coll> 
struct has_push_back { 
    template< 
     typename T, 
     typename = decltype(
      std::declval<T&>().push_back(std::declval<typename T::value_type>()) 
     ) 
    > 
    static std::true_type Test(int); 

    template<typename T> 
    static std::false_type Test(long); 

    using type = decltype(Test<Coll>(0)); 
    static constexpr bool value = type::value; 
}; 

Online Demo

Verwandte Themen