我想优化我正在编写的一个小程序/库,因为2周后我有点卡住了,现在想知道我脑子里的东西是否有可能就是这样。 (请保持温和,我没有太多的元编程经验。)
我的目标当然是让编译器完成某些计算,这样程序员 - 希望 - 只需要在程序中的某一点编辑代码,并让编译器“创建”所有样板。我确实有一个非常好的想法如何用宏来做我想要的东西,但是如果可能的话,我希望我能用模板做。
我的目标是: 假设我有一个使用程序员可以派生的类。在那里,他可以有多个传入和传出的数据类型,我想以某种方式注册,以便基类可以对它们进行操作。
class my_own_multiply : function_base {
in<int> a;
in<float> b;
out<double> c;
// ["..."] // other content of the class that actually does something but is irrelevant
register_ins<a, b> ins_of_function; // example meta-function calls
register_outs<c> outs_of_function;
}
我到目前为止的元代码是:(但它不是喷射工作/完成)
template <typename... Ts>
struct register_ins {
const std::array<std::unique_ptr<in_type_erasured>, sizeof...(Ts)> ins;
constexpr std::array<std::unique_ptr<in_type_erasured>, sizeof...(Ts)>
build_ins_array() {
std::array<std::unique_ptr<in_type_erasured>, sizeof...(Ts)> ins_build;
for (unsigned int i = 0; i < sizeof...(Ts); ++i) {
ins_build[i] = std::make_unique<in_type_erasured>();
}
return ins_build;
}
constexpr register_ins() : ins(build_ins_array()) {
}
template <typename T>
T getValueOf(unsigned int in_nr) {
return ins[in_nr]->getValue();
}
};
正如您所看到的,我想用可变数量的ins调用我的元模板代码。 (程序员可以在其中添加许多他喜欢的内容,但它们不会在运行时更改,因此可以在编译时“烘焙”)
元代码应该是创建一个数组,它具有ins数量的长度并被初始化,以便每个字段指向my_own_multiply类中的原始in。基本上给他一个可索引的数据结构,总是有正确的大小。并且我可以从function_base类访问以使用所有ins用于某些函数,这些函数也是可迭代的,使我的方便。
现在我已经研究了如何做到这一点,但我现在感觉我可能不会真的被允许在编译时“创建”这个数组,这样我就可以继续使用ins和b是非静态和非常数,以便我可以改变它们。无论如何,从我这边他们不一定是const,但我的compliler似乎不喜欢他们是自由的。我唯一需要const的是带指针的数组。但是使用constexpr可能会“让”我使它们成为常量?
好的,我会澄清我没有得到的: 当我试图创建我的元填充结构的“实例”时,它失败了,因为它期望各种const,constexpr等等。但我不想要它们,因为我需要能够改变大多数这些变量。我只需要这个元素来在编译时创建一个正确大小的数组。但是我不想为了实现这一点而牺牲必须使一切变为静态和常量。在这些条款下,这甚至是可能的吗?
答案 0 :(得分:0)
我没有得到你想到的所有东西(也是关于你的例子中的std::unique_ptr
),但也许这会有所帮助:
从C ++ 14(或C ++ 11,但严格限制)开始,您可以编写constexpr
函数,这些函数可以在编译时进行评估。作为一个先决条件(用简单的话说),所有参数都是由调用者传递的#34;必须是constexpr
。如果你想强制编译器替换那个&#34; call&#34;通过编译时计算的结果,您必须将结果分配给constexpr
。
编写常用函数(仅添加constexpr
)允许编写易于阅读的代码。此外,您可以对两者使用相同的代码:编译时计算和运行时计算。
C ++ 17示例(类似的事情在C ++ 14中是可能的,尽管std
中的某些内容只是缺少constexpr
限定符):
http://coliru.stacked-crooked.com/a/154e2dfcc41fb6c7
#include <cassert>
#include <array>
template<class T, std::size_t N>
constexpr std::array<T, N> multiply(
const std::array<T, N>& a,
const std::array<T, N>& b
) {
// may be evaluated in `constexpr` or in non-`constexpr` context
// ... in simple man's words this means:
// inside this function, `a` and `b` are not `constexpr`
// but the return can be used as `constexpr` if all arguments are `constexpr` for the "caller"
std::array<T, N> ret{};
for(size_t n=0; n<N; ++n) ret[n] = a[n] * b[n];
return ret;
}
int main() {
{// compile-time evaluation is possible if the input data is `constexpr`
constexpr auto a = std::array{2, 4, 6};
constexpr auto b = std::array{1, 2, 3};
constexpr auto c = multiply(a, b);// assigning to a `constexpr` guarantees compile-time evaluation
static_assert(c[0] == 2);
static_assert(c[1] == 8);
static_assert(c[2] == 18);
}
{// for run-time data, the same function can be used
auto a = std::array{2, 4, 6};
auto b = std::array{1, 2, 3};
auto c = multiply(a, b);
assert(c[0] == 2);
assert(c[1] == 8);
assert(c[2] == 18);
}
return 0;
}