Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enable a function template in C++ whenever an expression is undefined

Can a function template be enabled whenever some expression is undefined (e.g., xof 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.

like image 441
Xlea Avatar asked May 05 '15 15:05

Xlea


People also ask

How do you declare a template function?

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.

When a function is defined as a template?

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.

What the function template can accept?

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.

What is the need of template functions in C?

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.


2 Answers

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

like image 160
Daniel Frey Avatar answered Oct 05 '22 17:10

Daniel Frey


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.

like image 26
Yakk - Adam Nevraumont Avatar answered Oct 05 '22 17:10

Yakk - Adam Nevraumont