Roe*_*man 6 c++ variadic-templates c++20
在我正在编写的一段代码中,我收到了数据包uint8_t *和std::size_t组合。我可以根据从哪个文件描述符接收数据包来注册要使用这两个参数调用的函数。我使用 anstd::map<int, std::function<void(const uint8_t *, std::size_t)> > handlers来跟踪要调用哪个函数。
我希望能够(间接)使用任意参数注册函数。uint8_t *我已经有一个这样的函数来从和转换std::size_t为单独的变量:
int unpack(const uint8_t *buf, std::size_t len) { return 0; }
template <typename T, typename... Types>
int unpack(const uint8_t *buf, std::size_t len, T &var1, Types... var2) {
static_assert(std::is_trivially_copyable<T>::value, "unpack() only works for primitive types");
if (len < sizeof(T)) return -1;
var1 = *reinterpret_cast<const T *>(buf);
const auto sum = unpack(buf + sizeof(T), len - sizeof(T), var2...);
const auto ret = (sum == -1) ? -1 : sum + sizeof(T);
return ret;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:C++20 是否可以自动生成一个函数,该函数可以与uint8_t *传递std::size_t的函数所需的参数进行转换?
我希望能够做到这一点:
void handler(unsigned int i) { ... }
int main(int argc, char ** argv) {
/* some code generating an fd */
handlers[fd] = function_returning_an_unpacker_function_that_calls_handler(handler);
Run Code Online (Sandbox Code Playgroud)
编辑:我意识到我的答案有点太短了,正如一些人提到的(谢谢!)。
我想知道是否可以(如果可以,如何?)实现该function_returning_an_unpacker_function_that_calls_handler功能。我开始做这样的事情(凭记忆写的):
template<typename... Types>
std::function<void(const uint8_t * buf, std::size_t)>
function_returning_an_unpacker_function_that_calls_handler(std::function<void(Types...)> function_to_call) {
const auto ret = new auto([fun](const uint8_t * buf, std::size_t len) -> void {
const auto unpack_result = unpack(buf, len, list_of_variables_based_on_template_params);
if(unpack_result == -1) return nullptr;
function_to_call(list_of_variables_based_on_template_params);
};
return ret;
}
Run Code Online (Sandbox Code Playgroud)
这也是我提供该unpack功能的原因。我遇到的问题是我正在努力解决这个问题list_of_variables_based_on_template_params。我还没有找到任何方法来生成可以在两个地方相同地重复的变量列表。我也研究了一些使用std::tuple::tie和朋友,但我也没有看到解决方案。
这个答案与第一个答案非常相似,但它利用了 CTAD 的使用并std::function找出函数签名。
基于函数签名创建一个元组,并将参数类型和元组中的元素传递到unpack。
#include <iostream>
#include <tuple>
#include <type_traits>
#include <cstring>
#include <functional>
int unpack(const uint8_t *buf, std::size_t len) { return 0; }
template <typename T, typename... Types>
int unpack(const uint8_t *buf, std::size_t len, T &var1, Types&... var2) {
static_assert(std::is_trivially_copyable<T>::value, "unpack() only works for primitive types");
if (len < sizeof(T)) return -1;
var1 = *reinterpret_cast<const T *>(buf);
std::cout << "In unpack " << var1 << "\n";
const auto sum = unpack(buf + sizeof(T), len - sizeof(T), var2...);
const auto ret = (sum == -1) ? -1 : sum + sizeof(T);
return ret;
}
template<typename T, typename R, typename... Args>
std::function<void(const uint8_t * buf, std::size_t)>
unpack_wrapper_impl(T function_to_call, std::function<R(Args...)>) {
return [function_to_call](const uint8_t *buf, std::size_t len) -> void {
std::tuple<std::decay_t<Args>...> tup;
std::apply([&](auto&... args) {
unpack(buf, len, args...);
}, tup);
std::apply(function_to_call, tup);
};
}
template<typename T>
std::function<void(const uint8_t * buf, std::size_t)>
unpack_wrapper(T&& function_to_call) {
return unpack_wrapper_impl(std::forward<T>(function_to_call), std::function{function_to_call});
}
void test(int a, int b) {
std::cout << a << " " << b << "\n";
}
int main() {
int a= 5, b = 9;
uint8_t* buf = new uint8_t[8];
std::memcpy(buf, &a, 4);
std::memcpy(buf + 4, &b, 4);
auto f = unpack_wrapper(test);
f(buf, 8);
}
Run Code Online (Sandbox Code Playgroud)