[英]How to map generic templated compile-time functions
我想要某種結構/類型/映射,其中可以包含std::function
(包含我的回調),其類型在編譯時已知,而無需執行任何類型的虛擬 inheritance 或全部類型從基類型繼承。
例如,我希望GenericFunction
在這里保存std::function
而不擦除已知類型,因此我可以稍后在callback()
期間獲取類型
#include <unordered_map>
#include <string>
#include <functional>
#include <iostream>
// Example struct that I want
template<class CallbackDatatype>
struct GenericFunction{
GenericFunction(const std::function<void(const CallbackDatatype&)> callback)
: m_callback(callback)
std::function<void(const CallbackDatatype&)> m_callback;
static T datatypePlaceholder;
}
class Test
{
public:
Test() = default;
template <class CallbackDatatype>
void attachCallback(const std::string& key, const std::function<void(const CallbackDatatype&)>& callbackFn)
{
// How do I implement GenericFunction/a map that can hold GenericFunction??
m_callbackMap[key] = GenericFunction<CallbackDatatype>(callbackFn)
}
// Called during runtime
void callback(const std::string& key, void* payload)
{
const auto mapIter = m_callbackMap.find(key);
if (mapIter != m_callbackMap.end()) {
// I need to get the datatype of the argument specified in the std::function stored in m_callbackMap to use for deserialising my payload
decltype(mapIter->second.datatypePlaceholder) data = m_deserialiser.deserialise<decltype(mapIter->second.datatypePlaceholder)>(payload);
mapIter->second.m_callback(data);
}
}
private:
Deserialiser m_deserialiser;
std::unordered_map<std::string, GenericFunction> m_callbackMap;
};
struct SomeStruct{
int a;
int b;
float c;
};
int main(){
// Example int function (though I want to use more complicated structs)
const fn1 = [](const int& data) -> void {
std::cout << data << std::endl;
}
const fn2 = [](const SomeStruct& data) -> void {
std::cout << data.c << std::endl;
}
Test test;
test.attachCallback("Route1", fn1);
test.attachCallback("Route2", fn2);
return 0;
}
有沒有辦法做到這一點?
謝謝!
你可以做你想做的事,但不是使用字符串,而是使用類型標簽。
這是一個概念證明。
#include <tuple>
#include <utility>
#include <type_traits>
template <typename Tag, std::size_t I, std::size_t N, typename Tup>
struct FMapHelper {
static constexpr std::size_t helper() {
if constexpr (I < N) {
if constexpr (std::is_same_v<typename std::tuple_element_t<I,Tup>::first_type, Tag>) {
return I;
} else {
return FMapHelper<Tag, (I+1), N, Tup>::helper();
}
} else {
return N;
}
}
};
template <typename... TFs>
struct FMap {
std::tuple<TFs...> tfs;
template <typename Tag, typename F>
auto more(Tag, F&& f) const {
return FMap<TFs...,std::pair<Tag,F>>{std::tuple_cat(tfs, std::make_tuple(std::make_pair<Tag,F>(Tag{},std::forward<F>(f))))};
}
template <typename Tag>
auto get() const {
static constexpr std::size_t I = FMapHelper<Tag, 0, sizeof...(TFs), std::tuple<TFs...>>::helper();
if constexpr (I < sizeof...(TFs)) {
return std::get<1>(std::get<I>(tfs));
} else {
return nullptr; // no such tag found
}
}
};
這可以像這樣使用:
struct tag1 {};
struct tag2 {};
int main() {
struct Foo {};
// example functions
auto const foo = [](Foo const&) { return true; };
auto const fint = [](int i) { return i*7; };
// example map where e.g. tag1 refers to the foo function
auto const fmap = FMap<>{}.more(tag1{}, foo).more(tag2{}, fint);
// exmaple invocation
fmap.get<tag1>()(Foo{});
return fmap.get<tag2>()(6);
}
這是一個現場演示,顯示即使僅在 O1 上,編譯器也能完全優化這一點。
您可以存儲std::function<void(void*)>
,例如:
class Test
{
public:
Test() = default;
template <class CallbackDatatype>
void attachCallback(
const std::string& key,
const std::function<void(const CallbackDatatype&)>& callbackFn)
{
m_callbackMap[key] = [=](void* payload){
callbackFn(m_deserialiser.deserialise<CallbackDatatype>(payload));
};
}
// Called during runtime
void callback(const std::string& key, void* payload)
{
const auto mapIter = m_callbackMap.find(key);
if (mapIter != m_callbackMap.end()) {
mapIter->second(payload);
}
}
private:
Deserialiser m_deserialiser;
std::unordered_map<std::string, std::function<void(void*)>> m_callbackMap;
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.