【发布时间】:2020-12-15 13:11:32
【问题描述】:
考虑以下程序 (godbolt):
template <typename, typename>
struct is_same { static constexpr bool value = false; };
template <typename T>
struct is_same<T, T> { static constexpr bool value = true; };
template <typename T, typename U>
static constexpr bool is_same_v = is_same<T, U>::value;
using uintptr_t = unsigned long long;
template <int const* I>
struct Parameterized { int const* member; };
template <typename T>
auto create() {
static constexpr int const I = 2;
return Parameterized<&I>{ &I };
}
int main() {
auto one = create<short>();
auto two = create<int>();
if (is_same_v<decltype(one), decltype(two)>) {
return reinterpret_cast<uintptr_t>(one.member) == reinterpret_cast<uintptr_t>(two.member) ? 1 : 2;
}
return 0;
}
基于n4659(C++17最终工作草案):
§ 17.4 [temp.type]/1:
两个模板 ID 引用相同的类、函数或变量,如果:
- 它们的模板名称、操作符函数 ID 或文字操作符 ID 引用相同的模板并且
- 它们对应的类型模板参数是相同的类型和
- 它们对应的整数或枚举类型的非类型模板参数具有相同的值并且
- 它们对应的指针类型的非类型模板参数指的是同一个对象或函数,或者都是空指针值和
- 它们对应的指向成员类型的非类型模板参数指的是同一个类成员,或者都是空成员指针值和
- 它们对应的引用类型的非类型模板参数引用相同的对象或函数,并且
- 它们对应的模板模板参数指的是同一个模板。
我希望:
- 对于
create<T>的所有实例化都存在static constexpr int const I = 2;的单个实例,在这种情况下decltype(one)指代与delctype(two相同的类。 - 或者
static constexpr int const I = 2;的每个实例都有一个static constexpr int const I = 2;实例,在这种情况下,这两个实例引用不同的类。
然而,当使用 GCC 或 Clang(任何产生二进制文件的版本)时,main 的结果是 2 表示:
-
one和two使用相同的类。 -
create<T>()::I的另一个实例。
程序集列表确认创建了 2 个实例:_ZZ6createIsEDavE1I(又名create<short>()::I)和_ZZ6createIiEDavE1I(又名create<int>()::I)。
根据C++17标准,one和two的类型应该相同还是不同?
有趣的变化:将= 2 替换为= sizeof(T) 会导致类型不同(请参阅godbolt)。
【问题讨论】:
-
在探索将
char const*作为模板参数传递时发现,如stackoverflow.com/q/65275694/147192 中所示。 -
对于好奇的人,报告为gcc.gnu.org/bugzilla/show_bug.cgi?id=98288。让我们看看 GCC 开发人员的意见是什么。
-
ICE on gcc trunk,无论哪种方式都有错误。
-
@PasserBy:很好的发现。出于某种原因没有考虑测试主干...
-
也报告为bugs.llvm.org/show_bug.cgi?id=48517;与 clang 的奖励链接器问题。
标签: c++ c++17 language-lawyer