鉴于我想对某些数据执行过滤,如何避免在运行时生成此数据,但保持更改这些过滤器的大小和数据分布的灵活性,同时保持良好的清洁可重用代码。我知道我可以使用模板执行以下操作:
template <int x> class Filter
{
static const float f;
static const Filter<x-1> next;
inline float* begin(const Filter<x>& el){ return &f; }
inline float* end(const Filter<x>& el) { return (&f)+x+1; }
};
template <> class Filter<0>
{
static const float f;
inline float* begin(const Filter<0>& el){ return &f; }
inline float* end(const Filter<0>& el) { return (&f)+1; }
};
template <int x> const float Filter<x>::f = someDistribution(x);
template <> const float Filter<0>::f = someDistribution(0);
根据someDistribution(...),这确实会根据过滤器对象中的索引x在我的过滤器中生成数据。但是我的用途有一些缺点......
1)我认为我说的是,虽然这个数据不是在对象构造上生成的,但是在程序启动时会生成一次。 - 我可以忍受,但我宁愿过滤器在comiletime计算并在当时和那里烘烤(这对于浮点数据是否可能?)
2)过滤器不会实例化“下一个”成员,除非有一个遍历结构长度的成员函数(称为某处!),即
// inside template<int x> class Filter
inline void instantiate() const { next.instantiate(); };
// then inside template<> class Filter<0>
inline void instantiate() const { };
我必须做错了才需要插入实例化函数,这就失败了易于维护的条款。
编辑:我在这里关心的原因是我想确保实例化next
成员,这样我就可以使用开始和结束函数遍历静态'数组'。
首先,我如何解决问题2并取消实例化函数,其次是可以修复问题1,以便在编译时动态生成此数据并备份。
(注意我在类似的问题上我使用python预编译脚本生成包含过滤数据的源文件,但我不想在这里使用它,因为那是它自己的鱼!)
答案 0 :(得分:2)
由于您无法使用contexpr
...关于您的问题:
除非您正在搜索下一个最大的素数,否则您不应该在启动时进行简单计算。尝试测量它,你很可能发现初始化在不到一毫秒的时间内完成。
也就是说,在启动时计算的值表现为变量(每次使用时它们的值必须为asked
),而编译时常量的值始终是已知的。因此前者可能有点慢,但可能没有任何意义。
在引入不便之前,请先测量。
再次,你为什么关心?如果代码中的任何位置没有使用特定Filter
的{{1}}类型,为什么值应该在某处?
如果模板静态相互依赖是有问题的 - 在您的情况下它们没有,每个x
都是自主的。
说了这么多,一个很好的修补工具是http://gcc.godbolt.org/ - 你可以在输入时看到装配。它不支持MS编译器,但它可以让你很好地猜测编译器如何优化它们。
如果你的disrtibution很简单,那么它将是一个编译时常量:
f
集会(Clang):
#define someDistribution(x) x * x
template <int x> struct Filter
{
static const float f;
};
template <int x> const float Filter<x>::f = someDistribution(x);
int main()
{
return Filter<200>::f + Filter<100>::f;
}
如果您将main: # @main
movl $50000, %eax # imm = 0xC350
ret
更改为函数,即使是内联函数,您也会看到必须进行计算。
答案 1 :(得分:-1)
您可以使用可变参数模板获取拼图的一部分。一旦将integer_sequence支持添加到标准库,您就可以使用它而不是seq / gen_seq。
#include <array>
#include <iostream>
using namespace std;
template<size_t... Is> struct seq {};
template<size_t N, size_t... Is> struct gen_seq : gen_seq<N - 1, N - 1, Is...> {};
template <size_t... Is> struct gen_seq<0, Is...> : seq<Is...>{};
template<typename Func, size_t... Is>
const array<float, sizeof...(Is)>& make_coeffs(Func f, seq<Is...>) {
static const auto coeffs = array<float, sizeof...(Is)>{ f(Is)... };
return coeffs;
}
float square(float x) { return x * x; }
int main() {
const auto coeffs = make_coeffs(square, gen_seq<10>{});
for (float x : coeffs) {
cout << x << " ";
}
cout << endl;
}
为了使这个编译时间而不是在启动时初始化,虽然你真的想要VS 2013没有的constexpr支持。这是constexpr version:
#include <array>
#include <iostream>
using namespace std;
template<size_t... Is> struct seq {};
template<size_t N, size_t... Is> struct gen_seq : gen_seq<N - 1, N - 1, Is...> {};
template <size_t... Is> struct gen_seq<0, Is...> : seq<Is...>{};
template<typename Func, size_t... Is>
constexpr array<float, sizeof...(Is)> make_coeffs(Func f, seq<Is...>) {
return array<float, sizeof...(Is)>{ f(Is)... };
}
constexpr float square(float x) { return x * x; }
int main() {
constexpr auto coeffs = make_coeffs(square, gen_seq<10>{});
static_assert(coeffs[3] == 9, "");
for (float x : coeffs) {
cout << x << " ";
}
cout << endl;
}