我正在尝试编写一些代码,要求我在容器类中有很多std::array
。这些数组的大小各不相同(如果重要的话,它们都是从2-16连续的),并且每个大小都只有一个。我想将它们放在容器类中,并能够使用模板访问它们。
用代码解释可能更容易。我想要这样的东西:
class ContainerClass {
public:
// I want to declare some number of arrays right here, all of different
// sizes, ranging from 2-16. I'd like to be able to access them as
// arr<2> through arr<16>.
// This code gives a compiler error, understandably.
// But this is what I'd think it'd look like.
template <size_t N> // I also need to find a way to restrict N to 2 through 16.
std::array<int, N> arr;
// An example method of how I want to be able to use this.
template <size_t N>
void printOutArr() {
for (int i = 0; i < N; i++) {
std::cout << arr<N>[i] << std::endl;
}
}
};
我希望代码扩展为好像其中只有15个数组(从2到16)。像这样,但是有模板:
class ContainerClass {
public:
std::array<int, 2> arr2;
std::array<int, 3> arr3;
std::array<int, 4> arr4;
std::array<int, 5> arr5;
// ... and so on.
};
据我了解,C ++支持变量模板,但似乎仅适用于类中的静态成员。是否有其他选择可以表现类似(最好开销尽可能小)?
如果您需要更多信息,请询问。
谢谢。
答案 0 :(得分:6)
我可以有非静态成员变量模板吗?
否。
但是,您可以使用模板来生成您所描述的成员列表。这是一个使用递归继承的示例:
template<class T, std::size_t base, std::size_t size>
class Stair;
template<class T, std::size_t base>
class Stair<T, base, base> {};
template<class T, std::size_t base, std::size_t size>
class Stair : Stair<T, base, size - 1> {
protected:
std::array<T, size> arr;
public:
template<std::size_t s>
std::array<T, s>& array() {
return Stair<T, base, s>::arr;
}
};
int main()
{
Stair<int, 2, 10> s;
auto& arr = s.array<9>();
答案 1 :(得分:0)
我认为我可能有一个使用递归模板和std::tuple的解决方案。我使用gcc 7.3.0进行了编译和测试。
这使我感到肮脏,但似乎可以正常工作。
#include <iostream>
#include <array>
#include <tuple>
#include <type_traits>
// Forward declare A since there is a circular dependency between A and Arrays
template <size_t size, size_t start, typename... T>
struct A;
// If size is greater than start define a type that is an A::ArrayTuple from the
// next step down (size - 1) otherwise type is void
template <size_t size, size_t start, typename E, typename... T>
struct Arrays {
using type = typename std::conditional<(size > start),
typename A<size-1, start, E, T...>::ArrayTuple,
void
>::type;
};
// Use template recursion to begin at size and define std::array<int, size>
// to add to a tuple and continue marching backwards (size--) until size == start
// When size == start take all of the std::arrays and put them into a std::tuple
//
// A<size, start>::ArrayTuple will be a tuple of length (size - start + 1) where
// the first element is std::array<int, start>, the second element is
// std::array<int, start + 1> continuing until std::array<int, size>
template <size_t size, size_t start, typename... T>
struct A {
using Array = typename std::array<int, size>;
using ArrayTuple = typename std::conditional<(size == start),
typename std::tuple<Array, T...>,
typename Arrays<size, start, Array, T...>::type
>::type;
};
// This specialization is necessary to avoid infinite template recursion
template <size_t start, typename... T>
struct A<0, start, T...> {
using Array = void;
using ArrayTuple = void;
};
template <size_t size, size_t start = 1>
class Container {
public:
using ArrayTuple = typename A<size, start>::ArrayTuple;
// Shorthand way to the get type of the Nth element in ArrayTuple
template <size_t N>
using TupleElementType = typename
std::tuple_element<N-start, ArrayTuple>::type;
ArrayTuple arrays_;
// Returns a reference to the tuple element that has the type of std::array<int, N>
template <size_t N>
TupleElementType<N>& get_array() {
// Static assertion that the size of the array at the Nth element is equal to N
static_assert(std::tuple_size< TupleElementType<N> >::value == N);
return std::get<N-start>(arrays_);
}
// Prints all elements of the tuple element that has the type of std::array<int, N>
template <size_t N>
void print_array() {
auto& arr = get_array<N>();
std::cout << "Array Size: " << arr.size() << std::endl;
for (int i = 0; i < arr.size(); i++) {
std::cout << arr[i] << std::endl;
}
}
};
int main() {
// Create a new Container object where the arrays_ member will be
// a tuple with 15 elements:
// std::tuple< std::array<int, 2>, std::array<int, 3> ... std::array<int, 16> >
Container<16,2> ctr;
auto& arr2 = ctr.get_array<2>();
arr2[0] = 20;
arr2[1] = 21;
//ctr.print_array<1>(); // Compiler error since 1 < the ctr start (2)
ctr.print_array<2>(); // prints 20 and 21
ctr.print_array<3>(); // prints 3 zeros
ctr.print_array<16>(); // prints 16 zeros
//ctr.print_array<17>(); // Compiler error since 17 > the ctr size (16)
//int x(ctr.arrays_); // Compiler error - uncomment to see the type of ctr.arrays_
return 0;
}
如果我取消声明尝试显示int x
类型的ctr.arrays_
的那一行的注释,则为编译器的输出:
so.cpp: In function ‘int main()’:
so.cpp:90:22: error: cannot convert ‘Container<16, 2>::ArrayTuple {aka std::tuple<std::array<int, 2>, std::array<int, 3>, std::array<int, 4>, std::array<int, 5>, std::array<int, 6>, std::array<int, 7>, std::array<int, 8>, std::array<int, 9>, std::array<int, 10>, std::array<int, 11>, std::array<int, 12>, std::array<int, 13>, std::array<int, 14>, std::array<int, 15>, std::array<int, 16> >}’ to ‘int’ in initialization
int x(ctr.arrays_); // Compiler error - uncomment to see the type of ctr.arrays_