C ++:我可以拥有非静态成员变量模板吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C ++:我可以拥有非静态成员变量模板吗?相关的知识,希望对你有一定的参考价值。

我正在尝试编写一些代码,要求我在容器类中有很多std::arrays。这些阵列都有不同的大小(如果重要的话,所有阵列都是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 ++支持变量模板,但它似乎只适用于类中的静态成员。是否存在可以表现相似的替代方案(最好是尽可能少的开销)?

如果您需要更多信息,请询问。

提前致谢。

答案

我可以拥有非静态成员变量模板吗?

没有。

但是,您可以使用模板生成您描述的成员列表。以下是使用递归继承的示例:

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>();
另一答案

我想我可能有一个使用递归模板和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_

以上是关于C ++:我可以拥有非静态成员变量模板吗?的主要内容,如果未能解决你的问题,请参考以下文章

类数据成员中可以使用模板参数推导吗?

非静态模板成员:可能吗?

我可以在C ++中的运行时初始化静态const成员吗?

设备代码中CUDA类静态成员的成语?

在 C++0x 中,非静态数据成员初始化器会覆盖隐式复制构造函数吗?

spring中静态类调用非静态对象的方法