Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ overloading template on assigning value or callback function

Trying to do something like...

template <class T>
struct Wrapper
{
    template <class U>
    void set(const U& u) { myT = u; }

    template <class F>
    void set(F f) { myT = f(); }

    T myT;
};

I know I need to use SFINAE here but how do I distinguish a callback parameter from a value parameter? It's safe to assume that a value can't be used as a callback.

I've tried enable_if with is_function, result_of, invoke_result, is_invocable, and others, but none of it works right. Is it even possible?

like image 206
Allen Ienus Avatar asked Nov 19 '19 05:11

Allen Ienus


People also ask

Can template function be overloaded?

You may overload a function template either by a non-template function or by another function template. The function call f(1, 2) could match the argument types of both the template function and the non-template function.

What are operator overloading in C++?

Operator Overloading in C++ In C++, we can make operators work for user-defined classes. This means C++ has the ability to provide the operators with a special meaning for a data type, this ability is known as operator overloading.

What is the difference between function templates and function overloading?

What is the difference between function overloading and templates? Both function overloading and templates are examples of polymorphism features of OOP. Function overloading is used when multiple functions do quite similar (not identical) operations, templates are used when multiple functions do identical operations.

What is difference between function overloading and templates which one should be preferred in C++?

Function overloading is used when multiple functions do similar operations; templates are used when multiple functions do identical operations. Templates provide an advantage when you want to perform the same action on types that can be different.


2 Answers

You can do it without SFINAE:

template<class U>
void set(const U& u) { 
    if constexpr (std::is_invocable_v<U>)
        myT = u();
    else
        myT = u;
}

or in a more generic way:

template<class U>
void set(U&& u) { 
    if constexpr (std::is_invocable_v<U>)
        myT = std::forward<U>(u)();
    else
        myT = std::forward<U>(u);
}
like image 195
Evg Avatar answered Sep 27 '22 19:09

Evg


Yes you can apply SFINAE with the help of std::is_invocable (since C++17).

template <class U>
std::enable_if_t<!std::is_invocable_v<U>> set(const U& u) { myT = u; }

template <class F>
std::enable_if_t<std::is_invocable_v<F>> set(F f) { myT = f(); }

LIVE

like image 36
songyuanyao Avatar answered Sep 27 '22 21:09

songyuanyao