Include C ++ function template whenever expression is undefined

Is it possible to activate the function template whenever any expression is undefined (for example, the x

type t

does not support stream before 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 include if the expression is defined, but not how to do it if the expression is undefined.

+3


source to share


2 answers


You need a helper that provides a boolean value that you can change:

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

+6


source


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 a metaprogramming template.

Then the actual code of the specific use is really clean. First, a simple alias decltype

:

template<class X>
using cout_result = decltype( std::cout << std::declval<X>() );

      

and then apply a test to it:

template<class X>
using can_cout_stream = test_apply< cout_result, X >;

      



The goal is to separate the metaprogramming pattern from actual use.

template<class T>
std::enable_if_t<!can_cout_stream<const T&>{}>
f(const T& x) 

      

I am free to use the power of C ++ 14 to keep things clean. All of them can be easily 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.

+2


source







All Articles