简体   繁体   中英

Checking member function overload existence from a template

Is it possible to check whether a class has a certain member function overload from within a template member function?

The best similar problem I was able to find is this one: Is it possible to write a template to check for a function's existence? As I understand it, this doesn't apply in to the case of checking for overloads of functions.

Here a simplified example of how this would be applied:

struct A;
struct B;

class C
{
public:
    template<typename T>
    void doSomething(std::string asdf)
    {
        T data_structure;

        /** some code */

        if(OVERLOAD_EXISTS(manipulateStruct, T))
        {
            manipulateStruct(data_structure);
        }

        /** some more code */
    }

private:
    void manipulateStruct(B& b) {/** some different code */};
}

My question would be if some standard way exists to make the following usage of the code work:

int main(int argc, const char** argv)
{
    C object;
    object.doSomething<A>("hello");
    object.doSomething<B>("world");
    exit(0);
}

The only methods I could think of would be to simply create an emtpy overload of manipulateStruct for struct A . Otherwise the manipulation method could of course also be put into the structs to be manipulated, which would make SFINAE an option. Let's assume both of these to not be a possiblity here.

Is there any way to get code similar to the above one to work? Does something similar to OVERLOAD_EXISTS exist, to let the compiler know when to add the manipulateStruct part to the generated code? Or is there maybe some way clever way to make SFINAE work for this case?

Testing overload existence (C++11)

Since C++11, you can use a mix of std::declval and decltype to test for the existence of a specific overload:

// If overload exists, gets its return type.
// Else compiler error
decltype(std::declval<C&>().manipulateStruct(std::declval<T&>()))

This can be used in a SFINAE construct:

class C {
public:
    // implementation skipped
private:
    // Declared inside class C to access its private member.
    // Enable is just a fake argument to do SFINAE in specializations.
    template<typename T, typename Enable=void>
    struct can_manipulate;
}

template<typename T, typename Enable>
struct C::can_manipulate : std::false_type {};

// Implemented outside class C, because a complete definition of C is needed for the declval.
template<typename T>
struct C::can_manipulate<T,std::void_t<decltype(std::declval<C&>().manipulateStruct(std::declval<T&>()))>> : std::true_type {};

Here I am ignoring the return type of the overload using std::void_t (C++17, but C++11 alternatives should be possible). If you want to check the return type, you can pass it to std::is_same or std::is_assignable .

doSomething implementation

C++17

This can be done with constexpr if :

template<typename T>
void doSomething(std::string asdf) {
    T data_structure;
    if constexpr (can_manipulate<T>::value) {
        manipulateStruct(data_structure);
    }
}

The if constexpr will make the compiler discards the statement-true if the condition evaluates to false. Without the constexpr , the compilation will require the function call inside the if to be valid in all cases.

Live demo (C++17 full code)

C++11

You can emulate the if constexpr behaviour with SFINAE:

class C {
    // previous implementation
private:
    template<typename T, typename Enable=void>
    struct manipulator;
}

template<typename T, typename Enable>
struct C::manipulator {
    static void call(C&, T&) {
        //no-op
    }
};

// can_manipulate can be inlined and removed from the code
template<typename T>
struct C::manipulator<T, typename std::enable_if<C::can_manipulate<T>::value>::type> {
    static void call(C& object, T& local) {
        object.manipulateStruct(local);
    }
};

Function body:

template<typename T>
T doSomething()
{
    T data_structure;
    // replace if-constexpr:
    manipulator<T>::call(*this, data_structure);
}

Live demo (C++11 full code)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM