Can a function template be enabled whenever some expression is undefined (e.g., x
of type t
is not streamable to std::cout
). Something like
template<typename t>
auto f(const t &x)
-> typename enable_if_undefined<decltype(std::cout << x)>::type;
Using SFINAE, I only see how to enable if the expression is defined, but not how to do it if the expression is undefined.
To instantiate a template function explicitly, follow the template keyword by a declaration (not definition) for the function, with the function identifier followed by the template arguments. template float twice<float>( float original ); Template arguments may be omitted when the compiler can infer them.
Function templates are similar to class templates but define a family of functions. With function templates, you can specify a set of functions that are based on the same code but act on different types or classes.
Explanation: As a template feature allows you to write generic programs. therefore a template function works with any type of data whereas normal function works with the specific types mentioned while writing a program. Both normal and template function accepts any number of parameters. 4.
Overall, implementing templates in C can make C code more readable, less redundant, and less prone to errors. It allows efficient development without the need to incorporate or switch to C++ or languages with builtin template systems, if desired.
You need a helper which provides a boolean value you can reverse:
template<typename, typename=void>
struct has_cout
: std::false_type {};
template<typename T>
struct has_cout<T, decltype(std::cout << std::declval<T>(),void())>
: std::true_type {};
template<typename T>
auto f(const T& x)
-> typename std::enable_if<!has_cout<T>::value>::type;
Live example
template<class...>struct types{using type=types;};
namespace details {
template<template<class...>class Z, class types, class=void>
struct test_apply:std::false_type{};
template<template<class...>class Z, class...Ts>
struct test_apply<Z,types<Ts...>,std::void_t<Z<Ts...>>>:
std::true_type
{};
};
template<template<class...>class Z, class...Ts>
using test_apply=details::test_apply<Z,types<Ts...>>;
is the metaprogramming boilerplate.
Then the actual use-case specific code is really clean. First, a simple decltype
alias:
template<class X>
using cout_result = decltype( std::cout << std::declval<X>() );
and then we apply the test to it:
template<class X>
using can_cout_stream = test_apply< cout_result, X >;
the goal here is to decouple the metaprogramming boilerplate from the actual use.
template<class T>
std::enable_if_t<!can_cout_stream<const T&>{}>
f(const T& x)
I liberally use C++14 features to make things a touch cleaner. They can all be easily (re)implemented in C++11 if your compiler doesn't have them.
template<bool b, class T=void>
using enable_if_t=typename std::enable_if<b,T>::type;
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;
should cover it.
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