如何在编译时创建具有函数签名的函数指针

How to create a function pointer having a function signature, possibly at compile time

本文关键字:函数 指针 编译 创建      更新时间:2023-10-16

我知道这件事。

但是,我没有两个函数可以比较,我有一个函数签名和一个函数指针

template<typename T, typename ... A>
using RequiredSignature = bool(T&, A ... a);
template<typename T, typename ... A>
using RequiredFP = bool(*)(T&, A ... a);

问:如何确保我收到的函数指针确实确认了所需的签名?在编译时。

更好的解决方案是不要使用模板参数推导加上虚拟参数,当您打算控制类型时。 只需将类型传递给需要它的模板参数...

template<typename T, typename U>
constexpr inline bool fp_matches_fp(U y)
{
T* x{};
return (sizeof(is_same_helper(x, y))) == (sizeof(yes));
}

你像使用它一样使用它

fp_matches_fp<required_sig>(ok_fun)

调用方不必创建虚拟函数指针,类型特征会处理它。 但是我们根本不需要虚拟函数指针...

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));
}

2

我将其添加为"另一个"答案,以便每个答案都更清晰。

// 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) ) ;

只是,我认为前一个(要(简单得多。

1

解决方案(当然(是 1. 定义和 2. 从给定的函数签名初始化函数指针。

using required_sig = RequiredSignature<int>;
/*
actually define and initialize the required FP
*/
required_sig* rfp{};
if (inner::fp_matches_fp(rfp, ok_fun))
{
// ... MATCH ...
}

真的太明显了,谢谢本·沃伊特。

3

如果你也有,请投票给我,但这是答案 3 :)我可能会删除前两个中的一个,但将它们全部 3 + Bens 概念和答案,提供了很好的时间顺序视图。

与我的第二个答案一样,我正在使用std::common_type.这种变体只是更现代、更干净。

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>{}();
}

这是用法

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) );

或者不那么时髦的变化:

static_assert( signature_fp_match< bool(int&) >(ok_fun) );

对于更通用的实用程序,signature_fp_match重命名为have_common_type或任何您喜欢的内容。