从非类型模板参数声明 constexpr 数组的可移植方法

Portable way to declare constexpr array from non-type template arguments

本文关键字:数组 constexpr 可移植 方法 声明 参数 类型      更新时间:2023-10-16

我使用这种方法一段时间来做一些编译时的c-string操作:

template<char... args> struct String {static const char data[sizeof...(args)+1];};
template<char... args> constexpr const char String<args...>::data[sizeof...(args)+1] = {args...,''};

它适用于所有符合 c++11 的编译器,但是我最近发现 clang 不会将访问data成员视为 constexpr 常量:

enum Foo {
Bar = String<'f','o','o'>::data[1]
// read of non-constexpr variable 'data' is not allowed in a constant expression (clang)
// works fine (gcc)
};

但是,如果我像这样重写我的结构:

template<char... args> struct String {static constexpr const char data[sizeof...(args)+1] = {args...,''};};

它可以在gcc和clang上工作。

问题是,第二种方法仅适用于 c++17,我希望它至少与 c++14 兼容。有什么办法吗?

在这种情况下,找出哪个编译器是正确的以及为什么也会很好。我已经搜索了规范,但没有找到第一种方法不应该是constexpr的任何理由。

问题是static const char不是constexpr!在这种情况下,叮当似乎就在这里!

如果你这样写:

template<char... args> struct String {
static constexpr char data[sizeof...(args)+1]={args...,''};
};

enum Foo {
Bar = String<'f','o','o'>::data[1]       
};
int main()
{
std::cout << Foo::Bar << std::endl;
}

它在 C++11 中适用于 clang 和 gcc。

顺便说一句:这让我想知道为什么两个编译器都没有抱怨在这种情况下data[]的重复定义。

由于您直接初始化数组,因此无需再给出显式大小。因此,您可以简化为:

template<char... args> struct String {static constexpr char data[]{args...,''};};

编辑:当我得到你的评论时,我也尝试了较旧的编译器版本并遇到了同样的麻烦。但是使用 gcc 7.1 我可以编译该版本:

template<char... args> struct String {static constexpr char data[sizeof...(args)+1]={args...,''};};
template<char... args> constexpr char String<args...>::data[sizeof...(args)+1];

希望对您有所帮助!

据我所知,constexpr成员的直接初始化也可以在 C++11 中工作

template<char... args>
struct String {
static constexpr const char data[sizeof...(args)+1] {args...,''};
};