c++ - 存储可变模板参数并将它们传递给 lambda

标签 c++ lambda variadic-templates

我正在尝试用 C++ 做一些可怕的事情。

我有一个函数 f(void*, ...) 需要接受指向 intdouble 等的指针。我有很多这样的结构:

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>{}
    );
}

瞧瞧!我们可以用您想要的确切语法来调用这个东西。当然,所有看起来像错误检查的东西都留给读者作为练习:)

Live demo on Coliru

关于c++ - 存储可变模板参数并将它们传递给 lambda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48463657/

相关文章:

c++ - 单击上下文菜单项时运行程序

c++ - 如何包装 std::function 并轻松访问其返回和参数类型?

c++ - fstream ifstream 我不明白如何将数据文件加载到我的程序中

c++ - 将迭代器获取到泛型类 : HOW TO 中的泛型容器

c++ - 是否实现定义了哪些算法可以接受可变的 lambda?

c++11 - boost 日志 : using c++11 lambda expression to filter severity level

arrays - 模板化多维数组

c++ - 尝试将函数作为参数传递时未解析的重载函数类型

c++ - 格式化输出到 C++ ostringstream 对象

python - Pandas Dataframe groupby + agg + lambda + unique 抛出 ValueError