What is the canonical way to remove a template function from the overload set if a particular free function does not exist. So 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.
Also how about the inverse remove a function from the overload if a free function does exist. So remove the function foo above if the function bar does exist?
Simple expressions like that one can be easily SFINAE'd with decltype
:
template <typename T>
auto foo( T t ) -> decltype(bar(t), void())
{
// Do stuff
}
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 trait can_bar
which is 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 the SFINAE does not mess up the foo
function apparent signature. The inverse 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 might want to can_bar<T&>
instead of T
if you are calling it in an lvalue context instead of forwarding it.
Some of the above is beyond C++11.
It uses a C++14 feature of enable_if_t
. Replace enable_if_t<blah>
with typename enable_if<blah>::type
in C++11, or write your own enable_if_t
.
It also uses a C++14 feature of 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 track for C++20, is similar to can_apply
above.
template <typename T, typename = decltype( bar( std::declval<T>() ), void() ) >
void foo( T t )
{
// Do stuff
}
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