C ++ detects the existence of free functions with explicit parameters

I am writing some type traits to see if a free function exists with a specific set of parameters. Functions have a signature that looks something like this:

template <class T> void func( SomeClass &, SomeType const & ); 

I know the values ​​for T , SomeClass and SomeType . I want the property to return true if this function exists specifically with these parameters, without using any implicit conversion.

I can easily write some code to determine if this function exists using SFINAE to try to call it, for example.

 // 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 by properly checking the return types of these functions. Since I pass SomeClass ( Y ) to the function here, ADL can allow the compiler to search in the appropriate namespaces so as not to get confused in the dummy version of func that I define for tests.

The problem I ran into is that since SomeType ( Z in the above test) is passed by a constant reference, it is allowed to implicitly convert other types. For example, someone can define a function such as: template <class T> void func( SomeClass &, double const & ); and for any arithmetic type for Z my test will pass. I would like this to be passed only when Z is a true type, in this case a double .

I tried to solve this problem using function pointers in a circuit similar to 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 will work fine, but the problem I am facing is that the later defined user version of func will not be tested by the test - it only sees the dummy func , which I need to determine for the compiler to be happy. Unfortunately, I cannot pass the SomeClass type here, so ADL cannot click to get &func<X> to search for later defined user-defined functions.

Is there any way to do this? There is no need to use function pointers in the solution, it just has to be a sign returning true if there is some free function with a precisely provided set of parameters.

For information 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 
+8
c ++ c ++ 11 sfinae function-pointers name-lookup
source share
1 answer

I was able to solve this using the following technique, thanks to the help of dyp:

This solution no longer uses 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 as:

 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 

When playing with conversion operators inside NoConvert , you can do this job by passing a link to a value, link, or permalink.

For example, in current use, when the conversion operator for NoConvert<std::string> triggered by the parameter value std::string , both overloads are valid and therefore there is ambiguity, which means that SFINAE will select this and allow std::false_type pass the test. In the case of a constant reference parameter, a permanent overload reference takes precedence and properly allows std::true_type The overload test std::true_type .

This solution also relies on the ability to use ADL to resolve the function name, which was not possible using the function pointer approach.

+7
source share

All Articles