【发布时间】:2019-07-10 04:47:24
【问题描述】:
这是我能生成的显示此行为的最小示例:
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::foo(int)' 的未定义引用
Clang 版本 4 到 7 似乎接受了这一点。
两个小改动让 GCC 接受它:
- 删除
constexpr operator""定义,或 - 将
operator""和foo构造函数更改为inline而不是constexpr。
这是否合法,GCC 是否有正当理由拒绝原样?
【问题讨论】:
-
编译所有.cpp文件是否也会出现问题(不通过共享库)
-
@M.M 是的,同样的问题。我会更新问题。
-
请注意,它适用于
-std=c++17。