C++ 函数到指针的隐式转换:哪个编译器是正确的? Clang 和 GCC 不同意
Posted
技术标签:
【中文标题】C++ 函数到指针的隐式转换:哪个编译器是正确的? Clang 和 GCC 不同意【英文标题】:C++ function-to-pointer implicit conversion: which compiler is right? Clang and GCC disagree 【发布时间】:2019-06-07 17:51:34 【问题描述】:template <typename Type, Type Func>
struct A
;
void func();
A<void(), func> a; // same result with A<void(), &func> a;
此代码使用 Clang(包括最新的 8.0.0)编译,但不使用 GCC(包括最新的 9.1)。
GCC 说:error: 'void()' is not a valid type for a template non-type parameter
哪个编译器是正确的,为什么?
更新
我猜 GCC 是错误的,因为在 Clang 和 GCC 上都可以编译以下代码:
template <void()>
struct A
;
void func();
A<func> a; // same result with A<&func> a;
因此与 GCC 在第一个示例中的报告相反,void()
似乎是“模板非类型参数的有效类型”
【问题讨论】:
可能相关:A<void(*)(), func> a;
有效
我想不涉及指针(但原始函数类型)并且 GCC 是正确的。这里有关于函数类型与函数指针的某种相关解释:***.com/questions/8573763/… 无论如何,我们需要语言律师来提供具体答案。编辑:A<void(&)(), func> a;
被编译器接受,A<void(&&)(), func> a;
再次被 clang 接受
在更新中非类型模板参数的类型为void(*)()
,因为它被调整了。 template<void()> struct A
等价于 template<void(*)()> struct A;
demo
【参考方案1】:
与function parameter type的情况类似,如果非类型模板参数的类型是函数类型,则调整为指向函数类型[temp.param]/8的指针:
类型为“T 数组”或函数类型 T 的非类型模板参数被调整为“指向 T 的指针”类型。
所以clang是对的。 GCC 错误报告已经存在bug #82773
只有当前的c++标准工作草案将模板参数substitution的过程识别为以下模板参数。因此可以说该标准并不明确,因为它没有指定在每次替换后执行类型调整。
【讨论】:
Clang 和 GCC 的区别在于它们如何处理第一个模板参数,而不是第二个。 Clang 将第一个模板参数从void()
转换为 void(*)()
,GCC 没有。
@BorisRasin 第一个参数在这两种情况下都是void()
。 Clang 对非类型模板参数而不是 GCC 进行调整。我仍在深入研究标准,看看在这种情况下是否也应该进行类型调整,但我怀疑不清楚。
他们都调整第二个参数完全相同。这具有完全相同的结果:A<void(), &func>
。区别在于它们如何处理第一个参数。
@BorisRasin 您混淆了术语“参数”和术语“参数”。第一个模板参数是Type
,其关联参数是void()
。第二个参数是Func
,它的关联参数是&func
。将第一个参数与其关联的参数替换为第二个参数后,第二个参数的类型为void()
。第二个参数 (&func
) 的类型是 void(*)()
。 Clang 将第二个参数类型从void()
调整为void(*)()
。所以参数&func
的类型匹配参数的类型...
@BorisRasin ... 对于 GCC,第二个参数类型未调整为 void(*)()
并且非类型模板参数不能具有函数类型,因此 GCC 会报错。以上是关于C++ 函数到指针的隐式转换:哪个编译器是正确的? Clang 和 GCC 不同意的主要内容,如果未能解决你的问题,请参考以下文章
C++,bool 转换是不是总是退回到 void* 的隐式转换?