关于静态模板化 constexpr 的 Clang 警告(未定义内联函数)
Clang warning about static templated constexpr (inline function is not defined)
我有以下 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;
}
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)
似乎 clang 没有看到,我实例化了 filledArray 函数。 如果我在 main 或任何其他函数中使用适当的模板参数调用 filledArray,警告就会消失,并且 clangOut 也会按预期打印。
- 我在这里做傻事吗?
- gcc 版本是否在做我想的(在编译时用 As 初始化上部)?
- 这是叮当声中的错误吗?
- 我在这里做傻事了吗?
是的,该函数filledArray()
总是调用非constexprstd::array:fill
,因此将其声明为constexpr
严格来说是一个错误(根据[dcl.constexpr]/5"程序格式不正确,不需要诊断")。
- gcc 版本是否在做我想的事情(在编译时用 As 初始化上部)?
许多编译器放宽了 [dcl.constexpr]/5 的要求,并在非 constexpr 上下文中使用时静默忽略constexpr
。但是通过优化,他们也可以很容易地看到内联调用,例如std::array
和std::array::fill()
的构造,并且很可能会评估你的函数编译时间,即使它没有被声明constexpr
(demo)。
- 这是 clang 中的错误吗?
是的,这是一个叮当错误(#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;
}
将f.me
更改为foo::me
也可以"修复"它。
作为解决方法,您可以将constexpr
更改为const
。
- 它正在做我想的那样吗? -> 否(通过设置断点进行测试)
以下内容确实如此(灵感来自数组初始化编译时 - Constexpr 序列的答案)
#include <array>
#include <iostream>
#include <utility>
template <typename T, T value>
constexpr T generate_ith_number(const std::size_t) {
static_assert(std::is_integral<T>::value, "T must to be an integral type");
return value;
}
template <typename T, T value, T... Is>
constexpr auto make_sequence_impl(std::integer_sequence<T, Is...>)
{
return std::integer_sequence<T, generate_ith_number<T, value>(Is)...>{};
}
template <typename T, T value, std::size_t N>
constexpr auto make_sequence()
{
return make_sequence_impl<T, value>(std::make_integer_sequence<T, N>{});
}
template <typename T, T... Is>
constexpr auto make_array_from_sequence_impl(std::integer_sequence<T, Is...>)
{
return std::array<T, sizeof...(Is)>{Is...};
}
template <typename Seq>
constexpr auto make_array_from_sequence(Seq)
{
return make_array_from_sequence_impl(Seq{});
}
typedef unsigned char uchar;
class A {
public:
template <size_t N, uchar value>
static inline constexpr std::array<uchar, N> filledArray() {
return make_array_from_sequence(make_sequence<uchar, value, N>());
}
// long route
std::array<uchar, 5> upper = A::filledArray<5, 'A'>();
// taking a short cut
std::array<uchar, 45> blah = make_array_from_sequence_impl(make_sequence<uchar, 'A', 45>());
void dummy() {A::filledArray<5, 'A'>();} // make clang happy
};
int main() {
A blah;
for (int i = 0; i < 5; ++i)
std::cout << blah.upper[i] << std::endl;
for (int i = 0; i < 45; ++i)
std::cout << blah.blah[i] << std::endl;
return 0;
}
这实际上也回答了#1。 是的,试图优化永远不会对性能至关重要的代码是愚蠢的,失败了,遇到编译器错误并浪费大量时间试图找到一个太冗长且难以阅读的解决方案。 :D
- 编译C++时未定义的引用
- vscode g++链路故障:体系结构x86_64的未定义符号
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- 不知道某个东西是否被忽略会引入未定义的行为吗
- 对C宏的未定义引用,但在定义它时会出现重新定义错误
- 为什么我会收到警告,指出函数已使用但未定义,以及已定义但未使用?
- G++ 编译器未为未定义的方法生成错误/警告
- 我正在尝试在我的类中创建一个静态成员,但编译器警告我它是未定义的
- 链接时突然收到maxrregcount警告和未定义的引用错误
- 关于静态模板化 constexpr 的 Clang 警告(未定义内联函数)
- C 17 GCC编译器为什么会发出有关未定义的警告
- 如果可能存在未定义行为,为什么编译器不警告您?
- 警告:#Warning qopenglfunctions.h与GLEW不兼容,GLEW定义将未定义[-Wcpp]
- GCC警告已声明但未定义的变量
- 可以在编译时警告未定义的行为
- 关于未定义操作的编译器警告
- NVCC/CUDA 3.1 - ghtr-default.h 泛洪"declared static"但未定义的警告
- 如果局部堆栈变量是未定义的行为,为什么编译器会发出有关返回对局部堆栈变量的引用的警告
- C++未定义的引用...还有警告:已弃用从字符串常量到 'char*' 的转换