iak*_*aks 2 c++ template-meta-programming c++20 ctad non-type-template-parameter
我有这门课
template <typename ValueType, std::size_t Size>
struct ArrayPrimitive
{
constexpr ArrayPrimitive(const ValueType (&array)[Size]) {
std::copy(array, array + Size, data_);
}
ValueType data_[Size];
};
Run Code Online (Sandbox Code Playgroud)
这是我尝试将字符串文字传递为 NTTP 的包装器。然后我利用 CTAD 声明这个变量模板
template <ArrayPrimitive array>
std::integral_constant<decltype(array), array> arr;
Run Code Online (Sandbox Code Playgroud)
然后在代码中使用它
for (auto i : arr<{{2,4,6}}>.value.data_) std::cout << i << std::endl;
它编译并正确打印所有值。
我使用的编译器是 gcc13.2,我知道它目前无法在 clang 上运行,因为 c++20 对 NTTP 类的支持还不存在。另外,VS Code 的代码分析器确实不喜欢模板实例化中的括号,这有点奇怪,因为它没有arr<"123">.
我想知道它是否符合标准并且不会因未来的变化而中断。
编辑:查看错误报告GCC bug 111277的答案,看来 GCC 确实实现了 CWG 2450,将其置于预期行为领域,但仅适用于这一个编译器。
EDIT2:如果我这样写的话,它似乎也可以用 MSVC 编译https://gcc.godbolt.org/z/1sThrse3x
该代码arr<{{2,4,6}}>在语法上无效。如果您查看template-argument的语法,那么您会注意到它不支持扩展到花括号初始化列表。arr<ArrayPrimitive{2, 4, 6}>现在你必须写。
GCC 允许的事实arr<{{2, 4, 6}}>可能与已知的GCC bug 57905有关。我提交了一个新的GCC bug 111277。铿锵拒绝了。
然而,这看起来是标准中的一个缺陷,如CWG 2450.braced -init-list as a template-argument中所示。该问题目前处于起草状态,这意味着已达成非正式共识,但尚未有解决该问题的准确措辞。
您建议的变量模板非常具体,可以概括为适用于所有类型的常量。也不需要创建 type 的变量模板std::integral_constant。std::integral_constant例如,仅在创建类型别名模板时才需要。
你可以写:
template <auto value>
inline constexpr decltype(value) constant;
Run Code Online (Sandbox Code Playgroud)
注意:C++ 提案中已建议使用std::constant与此类似的类型别名,但未成功。
如果你无论如何都不会写arr<{2, 4, 6}>,那么你也可以使用constant上面的变量模板,比如constant<std::array{2, 4, 6}>. 这在语法上是有效的,因为std::array{2, 5, 6}它是一个有效的后缀表达式,由简单类型说明符和花括号初始化列表组成。
如果你想要的只是类似的东西for (int x : arr<{{2,4,6}}>),你也可以写
for (int x : {2, 4, 6})这依赖于std::initializer_listfor (int x : arr<int>{2, 4, 6})arr别名模板在哪里template <typename T> using arr = T[]for (int x : std::array{2, 4, 6})变量模板的优点是它是静态的constexpr并且具有静态存储持续时间。但是,这对于小型数组(例如具有三个元素的数组)来说并不重要。