每个具有自定义函数的编译时间
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 建议的折叠表达式的用法。在这种状态下,我没有做任何优化,但我喜欢界面,这是我的主要目标。即使我认为它应该在没有任何开销的情况下可行。如果您看到此消息并有任何想法或建议,请联系我。
一些观察。
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;
}
摘要:
想象一个具有以下形式的问题:必须调用仿函数列表中具有相同参数的多个特定成员函数。这是一个很好的问题,可以用接口来解决(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 建议的折叠表达式的用法。在这种状态下,我没有做任何优化,但我喜欢界面,这是我的主要目标。即使我认为它应该在没有任何开销的情况下可行。如果您看到此消息并有任何想法或建议,请联系我。
一些观察。
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;
}