我有以下 C++ 代码:
#include <array>
#include <iostream>
typedef unsigned char uchar;
class A {
public:
template <size_t N, uchar value>
static inline constexpr std::array<uchar, N> filledArray() {
std::array<uchar,N> ret{};
ret.fill(value);
return ret;
}
std::array<uchar, 5> upper = A::filledArray<5, 'A'>();
};
int main() {
A blah;
for (int i = 0; i < 5; ++i)
std::cout << blah.upper[i] << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
g++ 编译它时没有警告,并且输出为 As,正如预期的那样。但 clang++-4.0 产生:
clang++-4.0 -std=c++14 main.cpp -o clangOut
main.cpp:9:47: warning: inline function 'A::filledArray<5, 'A'>' is not defined [-Wundefined-inline]
static inline constexpr std::array<uchar, N> filledArray() {
^
main.cpp:15:34: note: used here
std::array<uchar, 5> upper = A::filledArray<5, 'A'>();
^
1 warning generated.
/tmp/main-b6fac8.o: In function `A::A()':
main.cpp:(.text._ZN1AC2Ev[_ZN1AC2Ev]+0x15): undefined reference to `std::array<unsigned char, 5ul> A::filledArray<5ul, (unsigned char)65>()'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Run Code Online (Sandbox Code Playgroud)
似乎 clang 没有看到,我实例化了filledArray 函数。如果我在主函数或任何其他函数中使用正确的模板参数调用filledArray,警告就会消失,并且 clangOut 也会按预期打印。
- 我在这里做了什么蠢事吗?
是的,该函数filledArray()总是调用非 constexpr std::array:fill,因此constexpr严格来说声明它是一个错误(根据[dcl.constexpr]/5 “程序格式错误,无需诊断”)。
- gcc 版本是否按照我的想法执行(在编译时使用 As 初始化 upper)?
许多编译器放宽了[dcl.constexpr]/5constexpr要求,并在非 constexpr 上下文中使用它时默默地忽略它。std::array但通过优化,它们还可以轻松地查看内联调用,例如和的构造std::array::fill(),并且很可能会在编译时评估您的函数,即使它没有声明constexpr(demo)。
- 这是 clang 中的错误吗?
是的,这是一个 clang bug ( #18781 )。
Clang 无法编译static constexpr类成员。当 ODR 使用此类元素时,它无法正确“查看”。A::filledArray<5, 'A'>();为了验证,您可以将其自身放置在 内部的某个位置main(),这将“修复”编译(但不会修复格式错误)。
另一个例子:
#include <iostream>
struct foo
{
constexpr static const char* me = "foo";
};
int main ()
{
foo f;
std::cout << f.me << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
更改f.me为foo::me也可以“修复”它。
作为解决方法,您可以更改constexpr为const.
| 归档时间: |
|
| 查看次数: |
2375 次 |
| 最近记录: |