假设你有:
template<class T,int N>
struct A {
A(const B& b): /* what comes here */ {}
std::array<T,N> F;
};
F[]
在上述情况下,我需要使用构造函数的参数构造的每个元素b
。这很棘手,因为参数可能不是可以是编译时常量的类型,例如int
等。
这与是否可以根据完整的模板参数构造成员数组的元素不同?因为这里使用了用户定义的结构,因此我们需要它的运行时副本。
假设你有:
template<class T,int N>
struct A {
A(const B& b): /* what comes here */ {}
std::array<T,N> F;
};
F[]
在上述情况下,我需要使用构造函数的参数构造的每个元素b
。这很棘手,因为参数可能不是可以是编译时常量的类型,例如int
等。
这与是否可以根据完整的模板参数构造成员数组的元素不同?因为这里使用了用户定义的结构,因此我们需要它的运行时副本。
索引技巧也可以在这里应用,你只需要稍微转换一下:
template <std::size_t... Is>
struct indices {};
template <std::size_t N, std::size_t... Is>
struct build_indices
: build_indices<N-1, N-1, Is...> {};
template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};
template<class T,int N>
struct A {
template<std::size_t... Is>
A(const B& b, indices<Is...>) : F{{(void(Is),b)...}} {}
A(const B& b) : A(b, build_indices<N>{}) {}
std::array<T,N> F;
};
我们基本上忽略了索引的值,只使用包本身来执行扩展,即我们只关心包的大小。为此重用索引可能看起来像是滥用,因为我们对实际值不感兴趣,但我认为在这里重用机器很好。用于创建N
-element 包的任何其他构造看起来都相同,只是包很可能只包含零。
The build_indicies trick as shown by Xeo is clever and probably the best option if your compiler supports it.
Another option might be to allow the elements to be default constructed, then to destroy them and reconstruct them with placment new/uninitialized_fill:
template<class T,int N>
struct A {
A(const B& b) {
for (size_t i=0;i<N;++i) {
F[i].~T();
new (&F[i]) T(b);
}
}
std::array<T,N> F;
};
You could also use storage that wouldn't be initialized normally, to avoid the default construction:
template<class T,int N>
struct A {
typedef std::array<T,N> array_type;
std::aligned_storage<sizeof(array_type),alignof(array_type)>::type storage;
array_type &F() {
return reinterpret_cast<array_type&>(storage);
}
A(const B& b) {
// placement new/uninitialized_fill
}
};