为什么我的SFINAE表达式不再适用于GCC 8.2? [英] Why do my SFINAE expressions no longer work with GCC 8.2?
问题描述
我最近将GCC升级到8.2,并且我的大多数SFINAE表达式都停止了工作.
I recently upgraded GCC to 8.2, and most of my SFINAE expressions have stopped working.
以下内容略有简化,但演示了该问题:
The following is somewhat simplified, but demonstrates the problem:
#include <iostream>
#include <type_traits>
class Class {
public:
template <
typename U,
typename std::enable_if<
std::is_const<typename std::remove_reference<U>::type>::value, int
>::type...
>
void test() {
std::cout << "Constant" << std::endl;
}
template <
typename U,
typename std::enable_if<
!std::is_const<typename std::remove_reference<U>::type>::value, int
>::type...
>
void test() {
std::cout << "Mutable" << std::endl;
}
};
int main() {
Class c;
c.test<int &>();
c.test<int const &>();
return 0;
}
GCC的旧版本(不幸的是,我不记得之前安装的确切版本)以及Clang可以很好地编译上述代码,但是GCC 8.2给出了错误提示:
Older versions of GCC (unfortunately I don't remember the exact version I had installed previously) as well as Clang compile the above code just fine, but GCC 8.2 gives an error stating:
: In function 'int main()':
:29:19: error: call of overloaded 'test()' is ambiguous
c.test();
^
:12:10: note: candidate: 'void Class::test() [with U = int&; typename std::enable_if::type>::value>::type ... = {}]'
void test() {
^~~~
:22:10: note: candidate: 'void Class::test() [with U = int&; typename std::enable_if::type>::value)>::type ... = {}]'
void test() {
^~~~
:30:25: error: call of overloaded 'test()' is ambiguous
c.test();
^
:12:10: note: candidate: 'void Class::test() [with U = const int&; typename std::enable_if::type>::value>::type ... = {}]'
void test() {
^~~~
:22:10: note: candidate: 'void Class::test() [with U = const int&; typename std::enable_if::type>::value)>::type ... = {}]'
void test() {
通常,当不同的编译器和编译器版本以不同的方式处理同一代码时,我假设我正在调用未定义的行为.关于上述代码,标准有什么要说的?我在做什么错了?
As is usually the case when different compilers and compiler versions handle the same code differently I assume I am invoking undefined behavior. What does the standard have to say about the above code? What am I doing wrong?
注意:问题不是解决此问题的方法,我想到了几种方法.问题是为什么在GCC 8中不起作用-是标准未定义,还是编译器错误?
Note: The question is not for ways to fix this, there are several that come to mind. The question is why this doesn't work with GCC 8 - is it undefined by the standard, or is it a compiler bug?
注释2:由于每个人都在使用默认的void
类型的std::enable_if
,因此我将问题改为使用int
.问题仍然存在.
Note 2: Since everyone was jumping on the default void
type of std::enable_if
, I've changed the question to use int
instead. The problem remains.
注释3: 已创建GCC错误报告
推荐答案
这是我的看法.简而言之,clang是正确的,而gcc具有回归.
This is my take on it. In short, clang is right and gcc has a regression.
根据 [temp.deduct] p7 :
替换发生在函数类型和模板参数声明中使用的所有类型和表达式中. [...]
The substitution occurs in all types and expressions that are used in the function type and in template parameter declarations. [...]
这意味着无论包装是否为空,都必须进行替换.因为我们仍处于即时环境中,所以可以使用SFINAE.
This means that the substitution has to happen whether or not the pack is empty or not. Because we are still in the immediate context, this is SFINAE-able.
接下来,我们将可变参数确定为实际的模板参数;来自 [temp.variadic] p1
Next we have that a variadic parameter is indeed considered an actual template parameter; from [temp.variadic]p1
模板参数包是一个接受零个或多个模板参数的模板参数.
A template parameter pack is a template parameter that accepts zero or more template arguments.
和 [temp.param] p2 表示哪个非类型允许使用模板参数:
and [temp.param]p2 says which non-type template parameters are allowed:
非类型模板参数应具有以下类型之一(可选的cv限定):
A non-type template-parameter shall have one of the following (optionally cv-qualified) types:
-
一种类型为文字的,具有强大的结构等式([class.compare.default]),没有可变或易失的子对象,并且如果存在默认的成员运算符< =>,则为宣布公开
a type that is literal, has strong structural equality ([class.compare.default]), has no mutable or volatile subobjects, and in which if there is a defaulted member operator<=>, then it is declared public,
左值引用类型
包含占位符类型([dcl.spec.auto])的类型,或
a type that contains a placeholder type ([dcl.spec.auto]), or
推导的类类型([dcl.type.class.deduct])的占位符.
a placeholder for a deduced class type ([dcl.type.class.deduct]).
请注意,void
不符合要求,您的代码(发布时)格式不正确.
Note that void
doesn't fit the bill, your code (as posted) is ill-formed.
这篇关于为什么我的SFINAE表达式不再适用于GCC 8.2?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!