为什么我的SFINAE表达式不再适用于GCC 8.2? [英] Why do my SFINAE expressions no longer work with GCC 8.2?

查看:105
本文介绍了为什么我的SFINAE表达式不再适用于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;
}

C ++(铛)–在线尝试

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆