我正在尝试用 C++ 做一些可怕的事情。
我有一个函数 f(void*, ...)
需要接受指向 int
、double
等的指针。我有很多这样的结构:
void whatever() {
somelogicHere();
int a;
double b;
char c;
f(&a, &b, &c);
some(a);
actions(b);
onabc(c);
}
我想将那一堆 Action 和变量定义包装到某个模板中,并像这样调用它:
myTemplate([](int a, double b, char c) {
some(a);
actions(b);
onabc(c);
});
必须做的事情的小例子:
template<int S, typename ...A>
void magicTemplate(const char(&fmt)[S], std::function<void(A...)> callback)
{
char format[2 + S];
format[0] = 'O';
format[1 + S] = '\0';
int s = S;
memcpy(format + 1, fmt, S);
// next lines is just a random stuff that does not work
std::tuple<A...> local_arguments;
extractArgs(format, &local_arguments...); //pointers to arguments must be passed
callback(local_arguments...); // arguments must be passed
}
...并调用我的模板:
magicTemplate("iii", [](int a, double b, char c)
{
std::cout < a << std::endl;
std::cout < b << std::endl;
std::cout < c << std::endl;
});
第一件事 - 我的模板与这个参数不匹配,第二件事 - 我不知道 magicTemplate
的主体必须包含什么。
最佳答案
我从中得到了一些好处 parameter-detection code :)
让我们先完成这项工作——我们想从传递给 magicTemplate
的任何类型中获取参数类型列表:
namespace glk {
namespace tmp {
template <class T>
struct type_is {
using type = T;
};
template <class...>
using void_t = void;
// Pack of arbitrary types
template <class...>
struct pack { };
namespace detail_parameters {
template <class F, class = void_t<>>
struct parameters { };
template <class F>
struct parameters<F, void_t<decltype(&F::operator ())>>
: parameters<decltype(&F::operator ())> { };
template <class R, class... Params>
struct parameters<R(Params...)> : type_is<pack<Params...>>{ };
template <class R, class... Params>
struct parameters<R(*)(Params...)> : type_is<pack<Params...>>{ };
template <class T, class R, class... Params>
struct parameters<R(T::*)(Params...)> : type_is<pack<Params...>>{ };
template <class T, class R, class... Params>
struct parameters<R(T::*)(Params...) const> : type_is<pack<Params...>>{ };
}
// Retrieve the parameter list from a functionoid
template <class F>
using parameters = typename detail_parameters::parameters<
std::remove_reference_t<F>
>::type;
}
}
现在glk::tmp::parameters<F>
给我们一个glk::tmp::pack<T...>
每个T
对应一个参数。现在,假设我们已经有了,并实现了 magicTemplate
的实际主体。 :
template <std::size_t FmtSize, class AndThen, class... Args, std::size_t... ArgsIdx>
void magicTemplate(
char const (&fmt)[FmtSize], AndThen &&andThen,
glk::tmp::pack<Args...>,
std::index_sequence<ArgsIdx...>
) {
std::array<char, FmtSize + 1> fmtStr;
fmtStr[0] = 'O';
std::copy(fmt, fmt + FmtSize, fmtStr.data() + 1);
std::tuple<Args...> args;
std::scanf(fmtStr.data(), &std::get<ArgsIdx>(args)...);
std::forward<AndThen>(andThen)(std::get<ArgsIdx>(args)...);
}
(出于测试目的,我已将 extractArgs
替换为 std::scanf
,因为它们看起来非常相似)
现在只需一些管道即可实际生成所需的 std::index_sequence
:
template <std::size_t FmtSize, class AndThen, class... Args>
void magicTemplate(
char const (&fmt)[FmtSize], AndThen &&andThen,
glk::tmp::pack<Args...>
) {
return magicTemplate(
fmt, std::forward<AndThen>(andThen),
glk::tmp::pack<Args...>{},
std::index_sequence_for<Args...>{}
);
}
template <std::size_t FmtSize, class AndThen>
void magicTemplate(char const (&fmt)[FmtSize], AndThen &&andThen) {
return magicTemplate(
fmt, std::forward<AndThen>(andThen),
glk::tmp::parameters<AndThen>{}
);
}
瞧瞧!我们可以用您想要的确切语法来调用这个东西。当然,所有看起来像错误检查的东西都留给读者作为练习:)
关于c++ - 存储可变模板参数并将它们传递给 lambda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48463657/