#include <stdio.h>
#include <type_traits>
void print()
{
printf("cheers from print !\n");
}
class A
{
public:
void print()
{
printf("cheers from A !");
}
};
template<typename Function>
typename std::enable_if< std::is_function<
typename std::remove_pointer<Function>::type >::value,
void >::type
run(Function f)
{
f();
}
template<typename T>
typename std::enable_if< !std::is_function<
typename std::remove_pointer<T>::type >::value,
void >::type
run(T& t)
{
t.print();
}
int main()
{
run(print);
A a;
run(a);
return 0;
}
The code above compiles and print as expected:
cheers from print ! cheers from A !
what I would like to express is : "if the template is function then apply this function, else ...". Or in another formulation : having a version of the function for function templates, and a default version for non function templates.
so, this part seems somehow redundant, and could be "replaced" by a "else" condition :
template<typename T>
typename std::enable_if< !std::is_function<
typename std::remove_pointer<T>::type >::value,
void >::type
run(T& t)
would this exists ?
std::enable_if is a convenient utility to use boolean conditions to trigger SFINAE. It is defined as: template <bool Cond, typename Result=void> struct enable_if { }; template <typename Result> struct enable_if<true, Result> { using type = Result; };
std::enable_if can be used in many forms, including: as an additional function argument (not applicable to operator overloads) as a return type (not applicable to constructors and destructors) as a class template or function template parameter.
" typename " is a keyword in the C++ programming language used when writing templates. It is used for specifying that a dependent name in a template definition or declaration is a type.
What you are looking for is constexpr if. That will let you write the code like
template<typename Obj>
void run(Obj o)
{
if constexpr (std::is_function_v<std::remove_pointer_t<Obj>>)
o();
else
o.print();
}
Live Example
If you don't have access to C++17 but do have C++14, you can at least shorten the code you need to write using a variable template. That would look like
template<typename T>
static constexpr bool is_function_v = std::is_function< typename std::remove_pointer<T>::type >::value;
template<typename Function>
typename std::enable_if< is_function_v<Function>, void>::type
run(Function f)
{
f();
}
template<typename T>
typename std::enable_if< !is_function_v<T>, void>::type
run(T& t)
{
t.print();
}
Live Example
You can use the tag dispatch mechanism if you are limited to using C++11.
namespace detail
{
template<typename Function>
void run(std::true_type, Function& f)
{
f();
}
template<typename Object>
void run(std::false_type, Object& o)
{
o.print();
}
} // namespace detail
template<typename T>
void run(T& t)
{
constexpr bool t_is_a_function =
std::is_function<typename std::remove_pointer<T>::type >::value;
using tag = std::integral_constant<bool, t_is_a_function>;
detail::run(tag{}, t);
}
Working example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With