c++ - 对外部模板 constexpr 构造函数的未定义引用
问题描述
这是我可以生成的显示此行为的最小示例:
foo.h
#pragma once
#include <string>
template <int I>
struct foo
{
constexpr explicit foo(int k)
: j(k + I)
{ }
std::string to_string() const;
private:
int j;
};
extern template struct foo<0>;
constexpr foo<0> operator"" _foo0(unsigned long long int v)
{
return foo<0>(static_cast<int>(v));
}
foo.cpp
#include "foo.h"
template <int I>
std::string foo<I>::to_string() const
{
return std::to_string(j);
}
template struct foo<0>;
酒吧.h
#pragma once
#include "foo.h"
#include <vector>
template <typename T>
struct bar
{
explicit bar(int i);
private:
std::vector<T> vec;
};
extern template struct bar<foo<0>>;
酒吧.cpp
#include "bar.h"
template <typename T>
bar<T>::bar(int i)
{
vec.push_back(T{i});
}
template struct bar<foo<0>>;
用法如下:
主文件
#include "bar.h"
int main()
{
bar<foo<0>> b2(5);
}
在 GCC 下编译它(我已经尝试过 7.4.0 和 8.3.0):
g++-8 foo.cpp bar.cpp main.cpp -std=c++14 -Wall -Werror -o test
给出错误:
bar.cpp:(.text._ZN3barI3fooILi0EEEC2Ei[_ZN3barI3fooILi0EEEC5Ei]+0x3c): 对 `foo<0>::foo(int)' 的未定义引用
Clang 版本 4 到 7 似乎接受了这一点。
两个小改动让 GCC 接受它:
- 删除
constexpr operator""
定义,或 operator""
将和foo
构造函数都更改为inline
而不是constexpr
.
这合法吗,GCC 是否有正当理由拒绝这样做?
解决方案
我对您的资源进行了很多尝试,并得到了以下结果:
gcc9.1.0 编译没有任何问题!
现在对 gcc 8.3.0 感到好奇:
g++ main.cpp foo.cpp bar.cpp -std=c++14 -Wall // fails: undef reference
正如你提到的那样失败!
但没有 -Wall 它可以编译!
g++ main.cpp foo.cpp bar.cpp -std=c++14 // compiles, no linker error!
并且
g++ main.cpp foo.cpp bar.cpp -std=c++17 -Wall // compiles, no linker error!
我不知道为什么该标志-Wall
与生成的中间文件有任何关系。-Wall
永远不应该影响任何生成的代码,因为它只是一个诊断的东西。所以对我来说,这只是一个 gcc 错误!所以请填写错误报告!
推荐阅读
- go - 如何设置 google stackdriver 以尊重 kubernetes 的日志记录严重性?
- r - 如何在闪亮的 R 应用程序中实现 Google 身份验证?
- javascript - JS 函数没有返回预期的结果
- vba - 条件格式 - 数字存储为文本
- objective-c - 在应用程序购买用户按取消接收 SKErrorDomain 代码 = 2
- android - 如何在android中制作类似的小键盘布局
- javascript - 将 Props 传递给 this.props.children
- r - 正则表达式 R 的 IF 过滤器
- javascript - 按字母顺序对动态生成的表进行排序
- python - Beautiful Soup 基于超链接文本查找 href