2016-05-24 8 views
2

Ich schreibe eine Vorlage-basierte Klasse für Polynome. (Evaluation, einige Operationen zwischen Polynomials, Differenzierung, ...), wie folgt aus: template <typename _ty> class Polynomial{...C++ SFINAE Operator/Funktion Ergebnistyp überprüfen

Für die to_string Funktion (und das std::ostream -left-Shift-Override), musste ich überprüfen, ob _ty die < unterstützt -Operator (dh ja für reelle Zahlen, nein für komplexe Zahlen), damit die Zeichenkette schön formatiert werden kann. Dazu verwende ich diesen Code:

#include <type_traits> 

template <class _op, class... _ty, typename = decltype(std::declval<_op>()(std::declval<_ty>()...))> 
std::true_type impl_test(const _op&, const _ty&...) { return std::true_type(); } 
std::false_type impl_test(...) { return std::false_type(); } 
template <class> struct supports; 
template <class _op, class... _ty> struct supports<_op(_ty...)> : decltype(impl_test(std::declval<_op>(), std::declval<_ty>()...)){}; 

#define is_ineq_supported(type) supports<std::less<>(type, type)>() 

Kurz gesagt, is_ineq_supported(type) gibt ein std::true_type, wenn ein gültiges Überlastung für den < -Operator ist, und ein false_type, wenn nicht. Die entsprechenden Funktionen können dann mit einem true_type oder false_type als Unterscheidungs ​​Argumente, so aufgerufen werden:

template <typename _ty> void do_stuff(_ty arg, const std::true_type&) { 
    // do stuff with the '<'-operator 
} 

template <typename _ty> void do_stuff(_ty arg, const std::false_type&) { 
    // do stuff without the '<'-operator 
} 

template <typename _ty> void do_stuff(_ty arg) { 
    do_stuff(arg, is_ineq_supported(_ty)); 
} 

Ich habe auch eine Vector-Klasse, die den binären * -Operator mit dem Skalarprodukt Überlastungen, so dass es wieder ein double. Aber für ein Polynom macht es nur Sinn, Koeffizienten und Argumente zu haben, die denselben Typ zurückgeben, wenn sie miteinander multipliziert werden.

Mein Problem ist das folgende: Ich möchte eine Möglichkeit haben, zu überprüfen, ob die angegebene Operation einen bestimmten Typ zurückgibt. (Vielleicht ein ähnliches Makro?) Ich denke, das einfachste wäre etwas, das eine true_type zurückgibt, wenn der Ergebnistyp dem Argumenttyp und eine anderenfalls entspricht. Natürlich sind allgemeinere Lösungen noch besser.

Falls IDE und Compiler wichtig sind: Ich verwende Visual Studio 2015 mit Standardeinstellungen.

+0

„* (...) Wenn die angegebene Operation einen bestimmten Typ * "zurückgibt, wäre es vielleicht besser zu prüfen, ob der zurückgegebene Typ implizit in etwas umwandelbar ist? –

+4

'std :: is_same' (oder' std :: is_convertible')? – Jarod42

Antwort

0

Hier ist eine generische, plattformübergreifende Lösung mit fit::is_callable, die schließlich zu Boost hinzugefügt wird. Achten Sie auch auf std::is_callable in C++ 17.

keine Makros erforderlich:

#include <type_traits> 
#include <iostream> 
#include <fit/is_callable.hpp> 

// std::less doesn't SFINAE, so we make our own test 
struct less_test { 
    template<typename L, typename R> 
    auto operator()(L l, R r) -> decltype(l < r); 
}; 

template<typename T> 
using is_less_than_comparable = fit::is_callable<less_test, T, T>; 

// operator< version (replace with your implementation) 
template <typename T> constexpr auto 
do_stuff(T arg, const std::true_type&) { 
    return std::integral_constant<int, 0>{}; 
} 

// other version (replace with your implementation) 
template <typename T> constexpr auto 
do_stuff(T arg, const std::false_type&) { 
    return std::integral_constant<int, 1>{}; 
} 

template <typename T> constexpr auto 
do_stuff(T arg) { 
    return do_stuff(arg, is_less_than_comparable<T>{}); 
} 

struct foo {}; 

int main() { 

    //is not less-than comparable 
    static_assert(do_stuff(foo{}) == 1, ""); 

    //is less-than comparable 
    static_assert(do_stuff(0) == 0, ""); 
} 
0

Sie sollten wahrscheinlich Ihre Member-Methode Detektoren und verwenden Sie die meisten C++ 11-ishvoid_t basierte Lösung überdenken.

Das heißt, wenn ich Ihre Lösung zu aktualisieren hatte, wahrscheinlich der folgende Code ist ein brauchbarer Ansatz:

template <class _op, class _ret, class... _ty> 
typename std::enable_if<std::is_same<decltype(std::declval<_op>()(std::declval<_ty>()...)), _ret>::value, std::true_type>::type 
impl_test(const _op&, const _ty&...) { 
    return std::true_type(); 
} 

Dies funktioniert wie folgt:

struct S { int operator()() { return 42; } }; 

int main() { 
    assert((impl_test<S, int>(S{}))); 
    // this will give you an error at compile time 
    // assert((impl_test<S, double>(S{}))); 
}