C ++在编译时在两个变量之间交替

时间:2018-08-16 21:23:14

标签: c++ arrays vector c++17

假设您有一个对向量进行操作的类:

class Foo{
public:
    Foo() {
        m_dynamic_data.push_back(5);
        std::cout << m_dynamic_data[0] << std::endl;
    }
private:
    std::vector<int> m_dynamic_data;
};

在我的情况下,该类非常庞大,需要增加2500行代码。 此类的行为是动态的(因此std::vector)。但我也想提供一个“静态”实现(使用std::array)。因此,添加了std::size_t N,它现在应该控制何时使用哪个属性。

template<std::size_t N>
class Foo{
private:
    std::vector<int> m_dynamic_data;  //use this, when N == 0
    std::array<int, N> m_static_data; //use this, when N != 0
};

我不确定是否可以使它正常工作。使用#define不会完成这项工作(因为它无法更改)。 constexpr也不能被两个属性包围。最好的解决方案可能是提供一个基类,然后从中继承动态和静态的情况。但是在我接下来的几天里这样做之前,我想知道是否还没有一种技术。

我考虑过将两者都放入std::unique_ptr中,并且只构造相关的数组:

template<std::size_t N>
class Foo {
public:
    Foo() {
        if constexpr (N) {
            m_static_data_ptr = std::make_unique<std::array<int, N>>();
            (*m_static_data_ptr)[0] = 5;
            std::cout << (*m_static_data_ptr)[0] << std::endl;
        }
        else {
            m_dynamic_data_ptr = std::make_unique<std::vector<int>>(1);
            (*m_dynamic_data_ptr)[0] = 5;
            std::cout << (*m_dynamic_data_ptr)[0] << std::endl;
        }
    }
private:
    std::unique_ptr<std::vector<int>> m_dynamic_data_ptr;
    std::unique_ptr<std::array<int, N>> m_static_data_ptr;
};

我之前曾问过这种情况here。但这显然不是一个好方法。 (碎片存储,高速缓存未命中率)。 std::optional似乎也很有趣,但是它将sizeof(Foo)推到了我的目标太远了。

最终还使用了void指针:

template<std::size_t N>
class Foo {
public:
    Foo() {
        if constexpr (N) {
            m_data = malloc(sizeof(std::array<int, N>));
            (*static_cast<std::array<int, N>*>(m_data))[0] = 5;
            std::cout << (*static_cast<std::array<int, N>*>(m_data))[0] << std::endl;
        }
        else {
            m_data = new std::vector<int>;
            (*static_cast<std::vector<int>*>(m_data)).push_back(5);
            std::cout << (*static_cast<std::vector<int>*>(m_data))[0] << std::endl;
        }
    }

    ~Foo() {
        delete[] m_data;
    }
private:
    void* m_data;
};

但这似乎很脏[...] 因此,目标是在编译时使用任一数组结构。感谢您的帮助/建议!

3 个答案:

答案 0 :(得分:4)

您可以将Installer.RelatedProducts data 部分抽象到另一个类模板。

Foo

您必须将成员函数添加到template<std::size_t N> struct FooData { std::array<int, N> container; } template <> struct FooData<0> { std::vector<int> container; } template<std::size_t N> class Foo{ private: using DataType = FooData<N>; DataType data; }; 中以支持其他抽象。此类功能及其接口的数量取决于您在FooData中使用容器的方式。

答案 1 :(得分:2)

R Sahu的答案很好,但是您不需要通过结构间接访问容器。

template<std::size_t N>
struct FooData { using type = std::array<int, N>;};

template <>
struct FooData<0> { using type = std::vector<int>; };

template<std::size_t N>
using FooData_t = typename FooData<N>::type;

template<std::size_t N>
class Foo{
   private:
      FooData_t<N> data;
};

或者,您也可以使用std::conditional_t

template<std::size_t N>
class Foo{
   private:
      std::conditional_t<N==0, std::vector<int>, std::array<int, N>> data;
};

答案 2 :(得分:1)

您可能希望将此动态/静态“变形”与巨型2500行Foo类的其余部分隔离开来。我可以想象在std::array周围有一个小的包装程序来模仿std::vector的界面。它可以用作Foo的成员。如果将静态容量设置为前哨值0,则可以将其专门用于仅从实数std::vector中得出:

#include <cassert>
#include <cstddef>

#include <array>
#include <iostream>
#include <vector>

template<class value_type_, std::size_t capacity_>
struct StaticOrDynamic {
  using value_type = value_type_;
  static constexpr std::size_t capacity = capacity_;

  std::array<value_type, capacity> arr_{};
  std::size_t size_{0};

  constexpr void push_back(const value_type& x) {
    assert(size_ < capacity && "must not exceed capacity");
    arr_[size_++] = x;
  }

  constexpr const value_type_& at(std::size_t i) const {
    assert(i < size_ && "must be in [0, size)");
    return arr_[i];
  }

/* other members etc */
};

template<class value_type_>
struct StaticOrDynamic<value_type_, 0>// specialization for dynamic case
  : std::vector<value_type_>
{
  using std::vector<value_type_>::vector;
};

template<std::size_t capacity_>
struct Foo {
  static constexpr std::size_t capacity = capacity_;

  StaticOrDynamic<int, capacity> m_data_{};

  Foo() {// static version may be constexpr (without debug output)
    m_data_.push_back(5);
    std::cout << m_data_.at(0) << std::endl;
  }
};

int main() {
  Foo<5> static_foo{};
  Foo<0> dynamic_foo{};
}

类似的行为(由模板参数选择的静态/动态)is offered in, e.g., the Eigen library。我不知道它在那里如何实现。