我正在尝试制作一个从 std::map<uint64_t, std::function<void(T)>>
调用正确函数的函数路由器 map 。问题是,它只能找到具有特定类型函数签名的特定类型的函数。我希望它支持各种功能。
库本身:
#ifndef ENGINE_H
#define ENGINE_H
#include <iostream>
#include <map>
class Engine
{
public:
typedef std::uint64_t hash_t;
/* Register function to signal router. */
template<class T>
void attach(hash_t hash, void(*f)(T)) {
/* Cast function ptr to std::function. */
auto func = static_cast<std::function<void (T)>>(f);
signal_router<T>[hash] = func;
}
/* Call registerd function from signal router. */
template<class T>
void emit(hash_t hash, T&& param) {
try {
signal_router<T>[hash](param);
} catch (std::bad_function_call&) {
int status = -4;
std::cerr << "Signal router: no function implemented for parameter \""
<< abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status) << "\" " << '\n';
}
}
private:
template<typename T>
static std::map<hash_t, std::function<void (T)>> signal_router;
};
/* We must declare static instance outside of its class, altough it's private. */
template<typename T>
typename::std::map<uint64_t, std::function<void (T)>> Engine::signal_router;
#endif /* ENGINE_H */
用法:
#include <iostream>
#include <string>
#include <functional>
#include "engine.hpp"
void f1(int i) {
std::cout << "Hello " << i << '\n';
}
void f2(long i) {
std::cout << "Hello " << i << '\n';
}
void f3(std::string& i) {
std::cout << "Hello " << i << '\n';
}
int main()
{
Engine eng;
eng.attach(0, f1);
eng.emit(0, 1);
eng.attach(1, f2);
eng.emit(1, 10l);
eng.attach(2, f3);
std::string s = " world";
eng.emit(2, s);
return 0;
}
输出:
Hello 1
Hello 10
Hello world
这是正确的。
但是如果我改变void f3(std::string& i)
签名void f3(const std::string& i)
它失败。据我了解,模板函数是使用 const 参数创建的,但它在某些时候被剥离并且没有从函数映射中找到正确的函数。
如果我改变函数f3
参数 const std::string&
它输出:
Signal router: no function implemented for parameter "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >"
所以 const 被去掉了。
如何通过模板设计支持各种参数(const ref、ref、values 等)?
最佳答案
当我们最初附加函数时,如果函数参数是const
,那么也绑定(bind)一个可变版本是安全的:
template<class T>
void attach(hash_t hash, void(*f)(T)) {
/* Bind to signal rounter */
signal_router<T>[hash] = std::function<void(T)>(f);
/* Bind mutable version to signal router */
using PlainT = std::remove_reference_t<T>;
if(std::is_reference<T>::value && std::is_const<PlainT>::value) {
// Bind mutable version
using MutableT = std::remove_const_t<PlainT>&;
signal_router<MutableT>[hash] = std::function<void(MutableT)>(f);
}
}
然后,我们可以将f3
写成一个常量函数:
void f3(std::string const& i) {
std::cout << "Hello " << i << '\n';
}
现在,无论 std::string
是否为 const,main
都有效。
我们也可以使用模式匹配重写:
template<class T>
void attach(hash_t hash, void(*f)(T)) {
// if it's pass by value, add multiple binds for references
signal_router<T>[hash] = std::function<void(T)>(f);
signal_router<T&>[hash] = std::function<void(T&)>(f);
signal_router<T const&>[hash] = std::function<void(T const&)>(f);
signal_router<T&&>[hash] = std::function<void(T&&)>(f);
}
template<class T>
void attach(hash_t hash, void(*f)(T&)) {
signal_router<T&>[hash] = std::function<void(T&)>(f);
}
template<class T>
void attach(hash_t hash, void(*f)(const T&)) {
signal_router<T const&>[hash] = std::function<void(T const&)>(f);
signal_router<T&>[hash] = std::function<void(T&)>(f);
}
template<class T>
void attach(hash_t hash, void(*f)(T&&)) {
signal_router<T&&>[hash] = std::function<void(T&&)>(f);
}
关于c++ - 有没有办法在我的通用功能路由器设计中支持 'const reference' 作为功能签名参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55580060/