【发布时间】:2012-12-04 14:55:03
【问题描述】:
我正在编写代码来执行带有n 点的Gaussian integration,其中n 是编译时间常数。
对于给定的n,我知道如何计算横坐标和权重。对于每个不同的n,必须从头开始计算。
现在,我按照这些思路做一些事情:
// Several structs like this one (laguerre, chebyshev, etc).
template <size_t n>
struct legendre
{
static const size_t size = n;
static const double x[n];
static const double w[n];
};
template <typename Rule, typename F>
double gauss_quadrature (F&& f)
{
double acc = 0;
for (size_t j = 0; j < Rule::size; j++)
acc += Rule::w[j] * f (Rule::x[j]);
return acc;
}
这样使用:
double i = gauss_quadrature<legendre<12>> (f);
现在,我可以专门研究legendre<12> 的系数的翻译单元,方法是
template <>
const legendre<12>::x[12] = { ... };
template <>
const legendre<12>::w[12] = { ... };
一切都很好,只要我只使用 12 点 Gauss-Legendre。
现在,我正在尝试不同数量的点,并且我知道如何生成权重和节点。例如,我可以提供一个例程
void compute_legendre_coeffs (size_t n, double* w, double* x);
和:
- 当我调用
gauss_quadrature<legendre<n>>时,模板legendre<n>会自动实例化(就是这种情况)。 -
当
legendre<n>为某个编译时n实例化时,我希望在main 之前的某个时间点调用上面的compute_legendre_coeffs,以便它填充x和w成员数组。 我如何做到这一点?
我知道必须先定义数组:
template <size_t n>
const double legendre<n>::x[n] = {};
template <size_t n>
const double legendre<n>::w[n] = {};
但我想不出一种方法来初始化它们。任何人都有这样做的诀窍吗?
【问题讨论】:
-
延迟初始化的最佳方法是将其填充到一个静态函数中,该函数在第一次调用时初始化,然后通过引用返回数组。
typedef const double (&arr_ref)[n];和static arr_ref get_x(){ static const double x[n] = {}; static char c = (init(x),'0'); return x; }. -
我看不出将legendre 作为模板的意义。甚至高斯正交。与现场成员一起解决这个问题要容易得多。你有成千上万的 gaussian_quadratures,所以你负担不起课堂上的额外字段吗? (每个实例增加 2 个额外字节)
-
@BarnabasSzabolcs:关于我正在使用的特定编译器的实验证据表明,拥有
n和在编译时已知的数组,我的性能会更好。 -
不是 100% 确定,但您似乎并不真正需要 之前
main计算的系数,而是在第一次使用之前。对?如果是这种情况,您可以制作系数private并提供一个static访问器来确保数组的初始化
标签: c++ templates static-members