I\'m writing some type traits to see if a free function exists with a specific set of parameters. The functions have a signature that looks something like this:
<
I was able to solve this using the following technique, thanks to help from dyp:
This solution no longer makes use of function pointers and instead relies on a proxy class that prevents implicit conversion:
template <class Source>
struct NoConvert
{
template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
operator Dest () const = delete;
template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
operator Dest const & () const;
};
template <class> void func();
template <class A, class T, class U>
static auto test(int) -> decltype( func<A>( std::declval<T&>(), NoConvert<U>() ), std::true_type() );
template <class, class, class>
static std::false_type test(...);
template <class A, class T, class U>
static bool valid()
{
return std::is_same<decltype(test<A, T, U>(0)), std::true_type>::value;
}
which can be used like:
template <class T>
void func( B &, int const & );
template <class T>
void func( B &, std::string );
template <class T>
void func( A &, std::string const & );
std::cout << valid<A, B, int>() << std::endl; // true
std::cout << valid<A, B, std::string>() << std::endl; // false
std::cout << valid<A, A, std::string>() << std::endl; // true
By playing with the conversion operators inside of NoConvert
, you can make this work with passing by value, reference, or constant reference.
For example, in the current use, when the conversion operator for NoConvert<std::string>
is triggered by a value parameter of std::string
, both overloads are valid and thus there is ambiguity, meaning that SFINAE will cull this and allow the std::false_type
test to pass. In the case of a constant reference parameter, the constant reference overload has precedence and properly allows the std::true_type
test overload to pass.
This solution also relies on the ability to use ADL to resolve the name of the function, which was impossible with the function pointer approach.