629 Stimmen

Vorgefertigte Prüfung auf das Vorhandensein einer Klassenmitgliedfunktion?

Ist es möglich, eine Vorlage zu schreiben, die das Verhalten ändert, je nachdem, ob eine bestimmte Member-Funktion auf eine Klasse definiert ist?

Hier ist ein einfaches Beispiel dafür, was ich schreiben würde:

template<class T>
std::string optionalToString(T* obj)
{
    if (FUNCTION_EXISTS(T->toString))
        return obj->toString();
    else
        return "toString not defined";
}

Also, wenn class T hat toString() definiert ist, dann wird sie verwendet, ansonsten nicht. Der magische Teil, von dem ich nicht weiß, wie er funktioniert, ist der "FUNCTION_EXISTS"-Teil.

0voto

DisplayName Punkte 139

Ich habe nach einer Methode gesucht, die es erlaubt, den Strukturnamen irgendwie nicht zu binden has_member zum Namen des Mitglieds einer Klasse. Eigentlich wäre dies einfacher, wenn Lambda in unbewerteten Ausdrücken erlaubt wäre (dies ist nach dem Standard verboten), d.h. has_member<ClassName, SOME_MACRO_WITH_DECLTYPE(member_name)>

#include <iostream>
#include <list>
#include <type_traits>

#define LAMBDA_FOR_MEMBER_NAME(NAME) [](auto object_instance) -> decltype(&(decltype(object_instance)::NAME)) {}

template<typename T>
struct TypeGetter
{
    constexpr TypeGetter() = default;
    constexpr TypeGetter(T) {}
    using type = T;

    constexpr auto getValue()
    {
        return std::declval<type>();
    }
};

template<typename T, typename LambdaExpressionT>
struct has_member {
    using lambda_prototype = LambdaExpressionT;

    //SFINAE
    template<class ValueT, class = void>
    struct is_void_t_deducable : std::false_type {};

    template<class ValueT>
    struct is_void_t_deducable<ValueT,
        std::void_t<decltype(std::declval<lambda_prototype>()(std::declval<ValueT>()))>> : std::true_type {};

    static constexpr bool value = is_void_t_deducable<T>::value;
};

struct SimpleClass
{
    int field;
    void method() {}
};

int main(void)
{   
    const auto helpful_lambda = LAMBDA_FOR_MEMBER_NAME(field);
    using member_field = decltype(helpful_lambda);
    std::cout << has_member<SimpleClass, member_field>::value;

    const auto lambda = LAMBDA_FOR_MEMBER_NAME(method);
    using member_method = decltype(lambda);
    std::cout << has_member<SimpleClass, member_method>::value;

}

0voto

Elliott Punkte 1905

Vor C++20, einfache Optionen für einfache Fälle:

Wenn Sie wissen, dass Ihre Klasse standardmäßig konstruierbar ist, können wir die Syntax vereinfachen.

Wir beginnen mit dem einfachsten Fall: Standard konstruierbar und wir kennen den erwarteten Rückgabetyp. Beispielmethode:

int foo ();

Wir können die Typeigenschaft ohne declval :

template <auto v>
struct tag_v
{
    constexpr static auto value = v;
};

template <class, class = int>
struct has_foo_method : tag_v<false> {};

template <class T>
struct has_foo_method <T, decltype(T().foo())>
    : tag_v<true> {};

Demo

Beachten Sie, dass wir den Standardtyp auf int denn das ist der Rückgabetyp von foo .

Wenn es mehrere akzeptable Rückgabetypen gibt, fügen wir ein zweites Argument zu decltype die vom gleichen Typ wie die Standardeinstellung ist und das erste Argument außer Kraft setzt:

decltype(T().foo(), int())

Demo

(Die int ist unwichtig - ich verwende es, weil es nur 3 Buchstaben sind)

-2voto

Abhishek Punkte 9
template<class T>
auto optionalToString(T* obj)
->decltype( obj->toString(), std::string() )
{
     return obj->toString();
}

template<class T>
auto optionalToString(T* obj)
->decltype( std::string() )
{
     throw "Error!";
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X