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:
template <class T> void func( SomeClass &, SomeType const & );
I know ahead of time the values for T
, SomeClass
, and SomeType
. I want the trait to return true if this function exists with exactly these parameters, not using any implicit conversion.
I can easily write some code to detect whether this function exists by using SFINAE to attempt to call it, e.g.
// potentially in some namespace
template <class> void func(); // this is necessary since user implementations
// of func will not exist until after
// this has been defined
template <class X, class Y, class Z>
static auto test(int) ->
decltype( func<X>( std::declval<Y&>(), std::declval<Z const&>(), std::true_type());
template <class, class, class> static std::false_type test(...);
and appropriately testing the return types of those functions. Since I get to pass SomeClass
(Y
) to the function here, ADL can let the compiler look in the appropriate namespaces to not get confused by the dummy version of func
I define for the tests.
The problem I run into here is that since the SomeType
(Z
in the above test) is passed by constant reference, it is allowed to implicitly convert to other types. For example, someone could define a function like: template <class T> void func( SomeClass &, double const & );
and for any arithmetic type for Z
, my test will pass. I would like it to pass only when Z
is the true type, in this case a double
.
I tried to solve this by using function pointers in a scheme like the following:
// struct to prevent implicit conversion and enforce function signature
template <class Y, class Z>
struct NoConvert
{
using FPType = void (*)(Y&, Z const &);
explicit NoConvert( FPType );
};
template <class> void func(); // see note on why this is needed above
template <class X, class Y, class Z>
static auto test(int) -> decltype( NoConvert( &func<X> ), std::true_type() );
template <class, class, class>
static std::false_type test(...);
template <class X, class Y, class Z>
static bool value(){ return std::is_same<decltype(test<X, Y, Z>()), std::true_type>::value; }
In theory this would work great, but the problem I run into is that a later defined user version of func
will not be seen by the test - it only sees the dummy func
I need to define for the compiler to be happy. Unfortunately I don't get to pass the type SomeClass
here so ADL can't kick in to get &func<X>
to look up later defined user functions.
Is there any way I can accomplish this? The solution doesn't have to use function pointers, it just needs to be a trait that returns true if some free function exists with exactly a provided set of parameters.
For reference on desired behavior:
template <class T> void func( A &, int const & );
value<T, A, int>(); // return true
value<T, A, long>(); // return false
value<T, A, double>(); // return false
value<U, A, int>(); // return false
value<T, B, int>(); // return false