Nun, auf diese Frage gibt es bereits eine lange Liste von Antworten, aber ich möchte den Kommentar von Morwenn unterstreichen: es gibt einen Vorschlag für C++17, der es wirklich viel einfacher macht. Siehe N4502 für Details, aber als eigenständiges Beispiel betrachten Sie das Folgende.
Dieser Teil ist der konstante Teil, den Sie in eine Kopfzeile setzen.
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf.
template <typename...>
using void_t = void;
// Primary template handles all types not supporting the operation.
template <typename, template <typename> class, typename = void_t<>>
struct detect : std::false_type {};
// Specialization recognizes/validates only types supporting the archetype.
template <typename T, template <typename> class Op>
struct detect<T, Op, void_t<Op<T>>> : std::true_type {};
dann gibt es den variablen Teil, in dem Sie angeben, wonach Sie suchen (ein Typ, ein Mitgliedstyp, eine Funktion, eine Mitgliedsfunktion usw.). Im Fall der OP:
template <typename T>
using toString_t = decltype(std::declval<T>().toString());
template <typename T>
using has_toString = detect<T, toString_t>;
Das folgende Beispiel, entnommen aus N4502 zeigt eine aufwändigere Sonde:
// Archetypal expression for assignment operation.
template <typename T>
using assign_t = decltype(std::declval<T&>() = std::declval<T const &>())
// Trait corresponding to that archetype.
template <typename T>
using is_assignable = detect<T, assign_t>;
Im Vergleich zu den anderen oben beschriebenen Implementierungen ist diese recht einfach: ein reduzierter Satz von Werkzeugen ( void_t
y detect
) reicht aus, keine Notwendigkeit für haarige Makros. Außerdem wurde berichtet (siehe N4502 ), dass er messbar effizienter ist (Kompilierzeit und Compiler-Speicherverbrauch) als frühere Ansätze.
Hier ist ein Live-Beispiel . Es funktioniert gut mit Clang, aber leider folgten GCC-Versionen vor 5.1 einer anderen Interpretation des C++11-Standards, was zu void_t
nicht wie erwartet funktioniert. Yakk hat bereits für Abhilfe gesorgt: Verwenden Sie die folgende Definition von void_t
( void_t in der Parameterliste funktioniert, aber nicht als Rückgabetyp ):
#if __GNUC__ < 5 && ! defined __clang__
// https://stackoverflow.com/a/28967049/1353549
template <typename...>
struct voider
{
using type = void;
};
template <typename...Ts>
using void_t = typename voider<Ts...>::type;
#else
template <typename...>
using void_t = void;
#endif