Reputation: 1008
I do know about this.
But, I do not have two functions to compare, I have a function signature and a function pointer
template<typename T, typename ... A>
using RequiredSignature = bool(T&, A ... a);
template<typename T, typename ... A>
using RequiredFP = bool(*)(T&, A ... a);
Question: How do I make sure function pointer, I have received does confirm to the required signature? At compile time.
Upvotes: 1
Views: 179
Reputation: 1008
Vote me down if you have too, but here is answer number 3 :) I might remove one of the previous two but having them all 3 + Bens concept & answer, gives nice chronological view.
As in my second answer, I am using std::common_type
. This variant is just more modern and cleaner.
template< class, class = void_t<> >
struct
has_type : false_type { };
template< class T >
struct
has_type<T, void_t<decltype(declval<T::type>())>> : true_type { };
template<typename SIG, typename FP >
constexpr inline bool signature_fp_match(FP)
{
using c_t = common_type< SIG, FP >;
return has_type<c_t>{}();
}
Here is the usage
template<typename T, typename ... A>
using RequiredSignature = bool(T&, A ... a);
bool ok_fun(int& ) { return true; }
static_assert( signature_fp_match< RequiredSignature<int> >(ok_fun) );
Or the less snazzy variation:
static_assert( signature_fp_match< bool(int&) >(ok_fun) );
For a more generic utility rename signature_fp_match
to have_common_type
or whatever you fancy.
Upvotes: 0
Reputation: 1008
The solution is (of course) to 1. define and 2. initialize the function pointer from the given function signature.
using required_sig = RequiredSignature<int>;
/*
actually define and initialize the required FP
*/
required_sig* rfp{};
if (inner::fp_matches_fp(rfp, ok_fun))
{
// ... MATCH ...
}
Too obvious really, thanks Ben Voight.
Upvotes: 0
Reputation: 1008
I am adding this as "another" answer so that each one is clearer.
// https://stackoverflow.com/a/18682805/10870835
template<typename T>
class has_type
{
typedef struct { char c[1]; } yes;
typedef struct { char c[2]; } no;
template<typename U> static constexpr yes test(typename U::type);
template<typename U> static constexpr no test(...);
public:
static constexpr bool result = sizeof(test<T>(nullptr)) == sizeof(yes);
};
template<typename SIG, typename FP >
constexpr bool signature_fp_match(FP)
{
using c_t = common_type< SIG, FP >;
if (has_type<c_t>::result) return true;
return false;
}
// usage
template<typename T, typename ... A>
using RequiredSignature = bool(T&, A ... a);
bool ok_fun(int& ) { return true; }
static_assert( signature_fp_match<RequiredSignature<int> >(ok_fun) ) ;
It is just, I thought the previous one is (much) simpler.
Upvotes: 0
Reputation: 283614
The better solution is not to use template parameter deduction plus a dummy parameter, when you mean to control the type. Just pass the type to the template parameter that wants it...
template<typename T, typename U>
constexpr inline bool fp_matches_fp(U y)
{
T* x{};
return (sizeof(is_same_helper(x, y))) == (sizeof(yes));
}
You use it like
fp_matches_fp<required_sig>(ok_fun)
The caller doesn't have to create a dummy function pointer, the type trait takes care of it. But we don't need the dummy function pointer at all...
template<typename T>
yes& is_compatible_helper(T*); //no need to define it now!
template<typename T>
no& is_compatible_helper(...); //no definition needed!
template<typename T, typename U>
constexpr inline bool fp_matches_fp(U y)
{
return (sizeof(is_compatible_helper<T>(y))) == (sizeof(yes));
}
Upvotes: 1