Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In a template, if a dependent name is a function, call it

In my TClass<T>::foo() function, I'd like to invoke a T instance if and only if T is a function type.

#include <iostream>
#include <functional>

template<class T>
struct TClass
{
    TClass(T value) : value(value) {}
    T value;
    void foo()
    {
        // if(value is std::function)
        //     call function;
    }
};

int main()
{
    TClass<int> t1{0};
    t1.foo();
    TClass<std::function<void()>> t2{[](){ std::cout << "Hello, World!\n"; }};
    t2.foo();
}

How can I do that?

like image 751
Vox Box Avatar asked Jun 12 '18 17:06

Vox Box


People also ask

How do you call a function in a template?

Defining a Function Template A function template starts with the keyword template followed by template parameter(s) inside <> which is followed by the function definition. In the above code, T is a template argument that accepts different data types ( int , float , etc.), and typename is a keyword.

Which is dependent on template parameter?

Which is dependant on template parameter? Explanation: Base class is dependant on template parameter.

What happens when a function is defined as a template?

Function templates are special functions that can operate with generic types. This allows us to create a function template whose functionality can be adapted to more than one type or class without repeating the entire code for each type. In C++ this can be achieved using template parameters.

What is a dependent name?

A dependent name is a name that depends on the type or the value of a template parameter. For example: template<class T> class U : A<T> { typename T::B x; void f(A<T>& y) { *y++; } }; The dependent names in this example are the base class A<T> , the type name T::B , and the variable y .


Video Answer


1 Answers

In C++11, the easiest way to do this is to re-deduce the value through a helper function:

template <typename U>
auto foo_helper(U const& f, int) -> decltype(f()) {
    return f();
}

template <typename U>
void foo_helper(U const&, long) {}

void foo() {
    foo_helper(value, 0);
}

The conversion from 0 to int is better than its conversion to long, so if the first overload is viable - it will be preferred. If the first overload isn't viable, then we call the second one.


If you really care only about std::function, then we can just have simpler overloads:

void foo_helper(std::function<void()> const& f) {
    f();
}

template <typename T>
void foo_helper(T const&) { }

void foo() {
    foo_helper(value);
}
like image 107
Barry Avatar answered Nov 15 '22 06:11

Barry