每个具有自定义函数的编译时间

Compiletime for each with custom functions

摘要:

想象一个具有以下形式的问题:必须调用仿函数列表中具有相同参数的多个特定成员函数。这是一个很好的问题,可以用接口来解决(runtime_interface,换句话说,这些仿函数必须实现的功能要求)。我想讨论的问题是仿函数列表在编译时已知,但在进一步开发过程中可能会发生变化的情况。因为在这种情况下,如果像那样实现,即使所有要调用的函数在编译时都是已知的,也会支付运行时开销。

一般问题:

有什么方法可以解决给定的问题,而没有或只有很小的运行时开销。在不放弃模块化结构的情况下。 我认为真正有趣的是它只是

我的做法:

template <class data_t, class... type_list_t>
struct compile_time_for_each_ref_impl;

template <class data_t, class first_t, class... type_list_t>
struct compile_time_for_each_ref_impl<data_t, first_t, type_list_t...> {
    static void eval(const data_t& data, first_t& object, type_list_t... object_list)
    {
        std::apply(object, data);

        compile_time_for_each_ref_impl<data_t, type_list_t...>::eval(data, object_list...);
    }
};
template <class data_t>
struct compile_time_for_each_ref_impl<data_t> {
    static void eval(const data_t& data) {}
};

template <class data_t, class... type_list_t>
void compile_time_for_each(const data_t& data, type_list_t&... objects)
{
    compile_time_for_each_ref_impl<data_t, type_list_t...>::eval(data, objects...);
}

template <class data_t, class... type_list_t>
void compile_time_for_each(const data_t& data, std::tuple<type_list_t...>& objects)
{
    std::apply(
        [&data] (type_list_t... params) {
            compile_time_for_each_ref_impl<data_t, type_list_t...>::eval(data, params...);
        },
        objects);
}

我能做到的:


int data = 42

auto functor_1 = [] (int data) {std::cout << data;};
auto functor_2 = [] (int data) {data++; std::cout << data;};

compile_time_for_each(std::make_tuple(data), functor1, functor2);

我想写的代码是这样的::

struct functor1{
    void method1(int);

    int method2(double);
};


struct functor1{
    void method1(int);

    int method2(double);
};

template <class... functors_t>
struct main_mod{
    std::tuple<functors_t...> functors;

    void method1(int some_data){
        compile_time_for_each<method1, functors_t...>(some_data,functors);
    }

    void method2(int some_data){
        compile_time_for_each<method2, functors_t...>(some_data,functors);
    }
};

我的方法存在的问题:

我看不到一种方法可以将应该在仿函数上调用的函数的名称传递给 compile_time_for_each 调用。我可以做的是更改硬编码的函数名称(示例实现采用 operator() 因为它使代码更简单,但可以硬编码任何函数名称)所以我最终会得到一个 compile_time_for_each 函数我想使用的每个函数名称。

一个解决方案(我不太喜欢):

一个有效的解决方案是将整个事情变成一个宏,并在宏中设置函数的实际名称。

最后对我来说,这并不是真正的开销,而是无法正确表达这些东西。

我的实际实现稿:

它结合了@Aconcagua 的解析器思想和@max66 建议的折叠表达式的用法。在这种状态下,我没有做任何优化,但我喜欢界面,这是我的主要目标。即使我认为它应该在没有任何开销的情况下可行。如果您看到此消息并有任何想法或建议,请联系我。

https://godbolt.org/z/LfmSSb

一些观察。

1) 如果要编译时执行,则必须使用constexpr.

所以你的compile_time_for_each()必须定义constexpr如果你想要编译时可以执行

template <typename data_t, typename... type_list_t>
constexpr void compile_time_for_each (data_t const & data, type_list_t &... objects)
 { /* some potentially compile time code */  }

2) 一个constexpr函数可以在编译时和运行时执行;如果你想要在编译时执行的 impose ...也许还有其他方法,但我想到的最简单的模式是 return 来自函数的值

template <typename data_t, typename... type_list_t>
constexpr int compile_time_for_each (data_t const & data, type_list_t &... objects)
 {
   /* some potentially compile time code */

   return 1;
 }

并使用 returned 值初始化一个 constexpr 变量

constexpr auto x = compile_time_for_each(data, functor_1, functor_2);

3) 对于编译时执行,您需要编译时值,因此将 data 定义为 constexpr

constexpr int data = 42;

或其使用会阻止编译时执行。

4)不需要递归:你标记了C++17所以你可以使用模板折叠;举个例子

template <typename D, typename ... Fs>
constexpr int compile_time_for_each (D const & data, Fs const & ... funcs)
 {
   (std::apply(funcs, data), ...);

   return 0;
 }

5) iostream input/output 代码与编译时执行不兼容;所以下面的 lambdas

 auto functor_1 = [] (int data) {std::cout << data;};
 auto functor_2 = [] (int data) {data++; std::cout << data;};

无法在编译时执行。


以下是C++17的例子

#include <tuple>

template <typename D, typename ... Fs>
constexpr int ct_for_each (D const & data, Fs const & ... funcs)
 {
   (std::apply(funcs, data), ...);

   return 0;
 }

int main ()
 {
   constexpr int data = 42;

   auto constexpr functor_1 = [] (int data) { /* some_code_1 */ };
   auto constexpr functor_2 = [] (int data) { /* some_code_2 */ };

   // compile time error if you define functor_1 as follows
   // auto constexpr functor_1 = [] (int data) { std::cout << data << std::endl; };

   constexpr auto x = ct_for_each(std::make_tuple(data), functor_1, functor_2);

   (void)x; // to avoid "unused variable 'x'" warning
 }

使用 lambda 我设法非常接近您的意图,即使我未能提供精确匹配:

template<typename Executor, typename Data, typename ... Functors>
void for_each(Executor executor, Data const& data, Functors ... functors)
{
    // C++17 fold expression:
    (executor(functors, data), ...);
}

class C0
{
public:
    void test0(int) const { std::cout << "00" << std::endl; }
    void test1(int) const { std::cout << "01" << std::endl; }
};
class C1
{
public:
    void test0(int) const { std::cout << "10" << std::endl; }
    void test1(int) const { std::cout << "11" << std::endl; }
};

int main()
{
    for_each([](auto const& c, int data) { c.test0(data); }, 7, C0(), C1());
    for_each([](auto const& c, int data) { c.test1(data); }, 7, C0(), C1());
    return 0;
}