我有以下类,用于为函数类型的任何子集构建回调函数,无论是静态函数、lambda、带捕获列表的 lambda、静态类函数还是成员类函数。问题是它不需要重载,因为在将函数传递给模板化构造函数时没有参数解析:
template<typename... A>
class callback {
protected:
/// Unique identifying hash code.
size_t hash;
/// The function bound to this callback.
std::function<void(A...)> bound;
public:
/// Binds a static or lambda function.
template<class Fx>
void bind_callback(Fx func) {
bound = [func = std::move(func)](A... args) { std::invoke(func, args...); };
hash = bound.target_type().hash_code();
}
/// Binds the a class function attached to an instance of that class.
template<typename T, class Fx>
void bind_callback(T* obj, Fx func) {
bound = [obj, func = std::move(func)](A... args) { std::invoke(func, obj, args...); };
hash = std::hash<T*>{}(obj) ^ bound.target_type().hash_code();
}
/// Create a callback to a static or lambda function.
template<typename T, class Fx> callback(T* obj, Fx func) { bind_callback(obj, func); }
/// Create a callback to a class function attached to an instance of that class.
template<class Fx> callback(Fx func) { bind_callback(func); }
/// Compares the underlying hash_code of the callback function(s).
bool operator == (const callback<A...>& cb) { return hash == cb.hash; }
/// Inequality Compares the underlying hash_code of the callback function(s).
bool operator != (const callback<A...>& cb) { return hash != cb.hash; }
/// Returns the unique hash code for this callback function.
constexpr size_t hash_code() const throw() { return hash; }
/// Invoke this callback with required arguments.
callback<A...>& invoke(A... args) { bound(args...); return (*this); }
};
用法:(重载失败,删除重载并编译)
myclass {
public:
void function(float x) {}
void function(int x) {}
static inline void static_function(float x) {}
static inline void static_function(int x) {}
}
static inline void function(float x) {}
static inline void function(int x) {}
int main() {
myclass inst;
callback<int> mycallback(&inst, &myclass::function);
callback<int> mycallback(&function);
callback<int> mycallback(&myclass::static_function);
}
在 Together C & C++ discord 上的某人的帮助下,在
std::type_identity_t
中使用 C++20
的建议解决了问题(以及对使用 lambda 的捕获列表的轻微修改)。您可以使用 std::type_identity_t<...>
来解决重载函数的歧义类型。这用以下内容替换了原始构造函数——bind_callback
函数不需要此参数解析,因为它已经使用构造函数完成了,但是我们必须将它们移动到私有以避免手动重新绑定,我不这样做无论如何都不允许。
然而,使用
std::type_identity_t
对类型定义更加明确,强制重新定义构造函数以涵盖所有情况(静态、lambda、捕获列表 lambda、静态类和成员函数)。
private:
/// Binds a static or lambda function.
template<class Fx>
void bind_callback(Fx func) {
bound = [func = std::move(func)](A... args) { std::invoke(func, args...); };
hash = bound.target_type().hash_code();
}
/// Binds the a class function attached to an instance of that class.
template<typename T, class Fx>
void bind_callback(T* obj, Fx func) {
bound = [obj, func = std::move(func)](A... args) { std::invoke(func, obj, args...); };
hash = std::hash<T*>{}(obj) ^ bound.target_type().hash_code();
}
public:
/// Create a callback to a static or lambda function.
template<typename T>
callback(T* obj, std::type_identity_t<void (T::*)(A...)> func) { bind_callback(obj, func); }
/// Create a callback to a static or lambda function.
template<typename T>
callback(std::type_identity_t<void (T::*)(A...)> func) { bind_callback(func); }
/// Create a callback to a class function attached to an instance of that class.
template<typename Lx>
callback(Lx func) { bind_callback(func); }
/// Create a callback to a class function attached to an instance of that class.
callback(std::type_identity_t<void(A...)> func) { bind_callback(func); }