SFINAE removes function from overload set if free function / does not exist

What is the canonical way to remove a template function from an overload set if any particular free function does not exist. Therefore, I have a function

template <typename T> void foo( T t ) { // Do stuff } 

and I want to remove this from the overload set if a free function taking a parameter of type T say

 bar( T ) 

does not exist.

As well as about back removal of function from overload if there is a free function. So, remove the foo function above if the function bar exists?

+6
source share
3 answers

Simple expressions like this can be easily SFINAE'd with decltype :

 template <typename T> auto foo( T t ) -> decltype(bar(t), void()) { // Do stuff } 
+4
source
 namespace details { template<template<class...>class Z, class, class...Ts> struct can_apply:std::false_type{}; template<template<class...>class Z, class...Ts> struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...>:std::true_type{}; }; template<template<class...>class Z, class...Ts> using can_apply = details::can_apply<Z, void, Ts...>; template<class T> using bar_r = decltype( bar( std::declval<T>() ) ); template<class T> using can_bar = can_apply<bar_r, T>; 

this gives us a can_bar , which true iff bar(t) is a valid expression.

 template<class T> std::enable_if_t< can_bar<T>{}, int> =0 > void foo( T t ) {} 

which has the advantage that SFINAE will not spoil the visible signature of the foo function. The converse is easy:

 template<class T> std::enable_if_t< !can_bar<T>{}, int> =0 > void foo( T t ) {} 

Another advantage of this technique.

Note that you may want can_bar<T&> instead of T if you call it in the lvalue context rather than forwarding it.


Some of the above are C ++ 11.

It uses the C ++ 14 enable_if_t function. Replace enable_if_t<blah> with typename enable_if<blah>::type in C ++ 11 or write your own enable_if_t .

It also uses the C ++ 14 function std::void_t .

 template<class...>struct voider{using type=void;}; template<class...Ts>using void_t = typename voider<Ts...>::type; 

to write it in C ++ 11.

is_detected , which on a track for C ++ 20 is similar to can_apply above.

+2
source
 template <typename T, typename = decltype( bar( std::declval<T>() ), void() ) > void foo( T t ) { // Do stuff } 
+1
source

Source: https://habr.com/ru/post/1012375/


All Articles