使用模板在size_t和int之间进行隐式类型转换

Implicit type conversion between size_t and int using templates

本文关键字:之间 int 类型转换 size      更新时间:2023-10-16

我有一个编译时序列生成类(取自此处,并对其进行了一点修改(:

#include <cstddef>
template <int...>
struct sequence {};
template <int... Ns>
struct generator;
template <std::size_t Count, int... Ns>  // XXX (read below)
struct generator<Count, Ns...> {
using type = typename generator<Count - 1, Count - 1, Ns...>::type;
};
template <int... Ns>
struct generator<0, Ns...> {
using type = sequence<Ns...>;
};
template <std::size_t N>
using sequence_t = typename generator<N>::type;
int main() {
sequence_t<5> a;
return 0;
}

这在Visual Studio下编译良好(即使使用/permissive-开关(。但它在GCC下抛出错误:

g++: error: template argument '(int)Count' involves template parameter(s)
g++:  struct generator<Count, Ns...> {
...

它也在Clang下抛出错误:

clang++: error: ambiguous partial specializations of 'generator<0, 0, 1, 2, 3, 4>'
clang++:    using type = typename generator<Count - 1, Count - 1, Ns...>::type;
...
clang++: note: partial specialization matches [with Count = 0, Ns = <0, 1, 2, 3, 4>]
clang++: struct generator<Count, Ns...> {
clang++:
clang++: note: partial specialization matches [with Ns = <0, 1, 2, 3, 4>]
clang++: struct generator<0, Ns...> {

在将标记行中的size_t类型(标记为XXX (read below)(更改为int之后,每个人都正确地编译了此示例代码。

在这种情况下谁是对的?Visual Studio是因为它编译代码,还是GCC+Clang是因为它不允许编译代码?

为什么Visual Studio能够很好地编译示例?它是否比其他编译器有更宽松的隐式转换规则?还是有不同的原因?任何能让我指向文件的链接,如果能帮助我解码这些错误消息,也将不胜感激:(

这是由于活动语言缺陷CWG问题1647:

标准似乎对部分专业化中的非类型模板参数的类型是否必须与主模板的类型相同或是否允许转换保持沉默

在处理此问题时存在实施差异。。。

因此,这里没有合适的编译器,因为标准中不存在如何处理此类专业化的明确要求。

请注意,GCC和Clang由于不同的原因而偏离并未能通过本示例。演示:https://gcc.godbolt.org/z/41cbPePPW

Clang不喜欢两种专业中的一种:

error: ambiguous partial specializations of 'generator<0, 0, 1, 2, 3, 4>'

GCC完全忽略了struct generator<Count, Ns...>试图实例化主模板的专业化,但由于缺乏其定义而失败:

error: invalid use of incomplete type 'struct generator<5>'

GCC在2014年报告了相应的错误(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60679)并且目前正在等待C++标准的澄清。

正如问题所说,用int替换size_t在这里是最好的,可以解决所有问题,演示:https://gcc.godbolt.org/z/fY9hxsT7P