【发布时间】:2018-01-20 22:45:02
【问题描述】:
考虑以下代码:
#include <iostream>
template<class T>
struct foo {};
template<>
struct foo<int> {
static constexpr char value[] = "abcde";
};
template<class T>
struct bar {
static constexpr char value[] = "abcde";
};
template<class T>
struct baz {
static constexpr int value = 12345;
};
int main() {
char c = foo<int>::value[2];
char d = bar<int>::value[2];
int e = baz<int>::value;
std::cout << c << d << e << "\n";
}
当使用 clang++ -std=c++14 ./test_foo.cc 编译时,出现未定义符号的链接器错误:bar<int>::value 和 foo<int>::value。当我更改为clang++ -std=c++17 时,只有一个未定义的符号:foo<int>::value。我的 clang++ 版本是 5.0。
但是,当我尝试g++ -std=c++14 ./test_foo.cc 时,编译成功。我的 g++ 版本是 5.4.0。
我正好有两件事要问。
1) 从 C++ 标准的角度来看,哪个编译器的行为正确?
我已经搜索并阅读了许多 cppreference 页面,但没有发现任何与此现象真正相关的内容。特别是对于带有-std=c++17 的clang++,行为真的很奇怪,因为bar<int> 通过但foo<int> 失败,唯一的区别是foo<int> 是一个专业化。我从http://en.cppreference.com/w/cpp/language/constexpr 读到
在函数或静态成员变量(C++17 起)声明中使用的 constexpr 说明符意味着内联。
因此,模板专业化foo<int> 似乎没有理由失败。此外,我在链接之前查看了生成的目标文件,对foo<int>::value[2]; 的访问没有在编译时完成,正如人们所期望的那样。我高度怀疑 clang++ 编译器有问题。
2)如何处理这个clang++链接错误?
我尝试了类似Undefined reference to static constexpr char[] 的方法,但最后我找不到任何方法来克服这个链接错误。所以我只是想知道是否有办法让这个链接成功。
【问题讨论】:
-
使用 Visual Studio 2017 编译良好 - 奇怪的是,即使没有明确指定 C++14/C++17。
-
@CookiePLMonster g++ 也成功为 -std=c++11 编译。但是对于 clang++,可以通过上面链接中提到的技巧来避免 c++11 错误。但是,c++17版本我什至找不到办法让它编译。
标签: c++ c++14 constexpr clang++ c++17