这是我可以产生的显示这种行为的最小示例:
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>;
bar.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>>;
bar.cpp
#include "bar.h"
template <typename T>
bar<T>::bar(int i)
{
vec.push_back(T{i});
}
template struct bar<foo<0>>;
它的用法如下:
main.cpp
#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
。这合法吗?海湾合作委员会是否有正当理由拒绝该原状?
答案 0 :(得分:1)
我对您的消息来源进行了很多尝试,并获得了以下结果:
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错误!因此,请填写错误报告!