c++ - constexpr 数组初始化

标签 c++ constexpr

我定义并初始化了一个类似于以下的数据结构:

#include <vector>
#include <array>

struct SomeStruct {
    std::vector<int> vec;
};

int main() {
    std::array<SomeStruct, 2> arr {
        SomeStruct {
            .vec = {
                1, 2
            }
        },
        SomeStruct {
            .vec = {
                3, 4, 5
            }
        }
    };
}

这编译正确,但由于整个结构在编译时是已知的,我试图使它成为一个 constexpr

在前面的例子中简单地将 arr 声明为 constexpr 会导致错误:

main.cpp: In function ‘int main()’:
main.cpp:20:5: error: the type ‘const std::array’ of constexpr variable ‘arr’ is not literal
     };
     ^
In file included from main.cpp:2:0:
/usr/include/c++/7/array:94:12: note: ‘std::array’ is not literal because:
     struct array
            ^~~~~
/usr/include/c++/7/array:94:12: note:   ‘std::array’ has a non-trivial destructor

我猜这是因为 std::vector 没有 constexpr 构造函数/析构函数。

然后我尝试在包含结构上使用带有模板的 std::array:

#include <array>

template <int N>
struct SomeStruct {
    std::array<int, N> vec;
};

int main() {
    constexpr std::array<SomeStruct, 2> arr {
        SomeStruct<2> {
            .vec = {
                1, 2
            }
        },
        SomeStruct<3> {
            .vec = {
                3, 4, 5
            }
        }
    };
}

这也会导致错误:

main.cpp: In function ‘int main()’:
main.cpp:10:39: error: type/value mismatch at argument 1 in template parameter list for ‘template struct std::array’
     constexpr std::array<SomeStruct, 2> arr {
                                       ^
main.cpp:10:39: note:   expected a type, got ‘SomeStruct’
main.cpp:10:41: error: scalar object ‘arr’ requires one element in initializer
     constexpr std::array<SomeStruct, 2> arr {
                                         ^~~

但是我不能给 SomeStruct 模板参数,因为大小可能不同。

像这样定义 constexpr 数据结构的最佳方法是什么?

最佳答案

就像说here

Because std::array<T, N> is an aggregate, it can be initialized as a constexpr if and only if the underlying type T has a constexpr constructor (when presented with each initializer you provide).

作为std::vector没有 constexpr 构造函数 ( yet ),这是行不通的。

因此对于 C++20 之前的版本,这不适用于动态大小的 STL 容器。没有解决方案或快速修复。不要抱太大希望。

另一种方法是设计自己的 constexpr fixed-max-size Vector类(class)。例如

template <typename T, std::size_t N>
class Vector {
private:
   T values[N]{};
public:
   std::size_t size{ 0 };
   constexpr bool empty() const noexcept { return size == 0; }
   constexpr void clear() noexcept { size = 0; }

   constexpr T* begin() noexcept { return &values[0]; }
   constexpr T* end() noexcept { return &values[size]; }
   constexpr T const* cbegin() const noexcept { return &values[0]; }
   constexpr T const* cend() const noexcept { return &values[size]; }

   constexpr T& back() noexcept { return values[size - 1]; }

   constexpr T operator[] (int const loc) const noexcept { return values[loc]; }
   constexpr T& operator[] (int const loc) noexcept { return values[loc]; }

   constexpr void push_back(T const& value) noexcept { values[size++] = value; }

   constexpr void resize(int const newSize) noexcept {
       auto const diff = newSize - size;
       if (diff > 0) memset(end(), 0, diff * sizeof(T));
       size = newSize;
   }
};

这是我有时使用的...您需要添加一个 initializer_list构造函数。

编辑:快速测试...这似乎可以编译。

#include <array>

template <typename T, std::size_t N>
class Vector {
private:
   T values[N]{};
public:
    std::size_t size{ 0 };
    constexpr Vector(std::initializer_list<T> il) noexcept
     : size(std::distance(std::cbegin(il), std::cend(il)))
     {
         std::size_t i = 0;
         for(auto it = std::cbegin(il); it != std::cend(il); ++it) {
             values[i++]=*it;
         }
     }
};

struct SomeStruct {
    Vector<int,5> vec;
};

int main() {
    [[maybe_unused]]constexpr std::array<SomeStruct, 2> arr {
        SomeStruct {
            .vec = {
                1, 2
            }
        },
        SomeStruct {
            .vec = {
                3, 4, 5
            }
        }
    };
}

关于c++ - constexpr 数组初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58710630/

相关文章:

c++ - 线程矩阵乘法

c++ - 如何将 BYTE 数组转换为 char 数组以使用套接字 c++ 发送

c++ - 如何在头文件中使用用户定义的文字?

C++ 计数函数

c++ - 使用 print 函数输出重载的 << 运算符?

c++ - 为什么非常量 std::array::operator[] 不是 constexpr?

c++ - 为什么我不能使用 msvc 在模板类中声明静态 constexpr 变量?

c++ - 如何静态查询一个可能不存在的静态成员变量,提供一个默认值?

c++ - constexpr 的使用是否对非常量成员有效

c++ - 通过 Windows 管道写入进程 STDIN