19

我正在尝试在折叠表达式中使用任意函数,当我发现以下代码可以gccclang.

enum Enum {
    A = 3,
    B = 8,
    C = 5
};

namespace EnumMax {
    constexpr Enum operator>>=(const Enum left, const Enum right) {
        return left < right ? right : left;
    }
}

template<Enum ... enums>
constexpr Enum max() {
    using EnumMax::operator>>=;
    return (enums >>= ...);
}

constexpr Enum max_v = max<A, B, C>();

https://godbolt.org/z/-LOudM

似乎clang没有考虑重载运算符,而是尝试>>=在折叠表达式中使用正则运算符。

但是,如果改为拼写折叠表达式,clang则考虑重载运算符并且编译得很好:

constexpr Enum maxExplicit() {
    using EnumMax::operator>>=;
    return (A >>= (B >>= C));
}

这是一个clang错误吗?或者折叠表达式的拼写等价不完全等价?

4

1 回答 1

3

每个[expr.prim.fold]/ fold-operator

折叠运算符:其中之一

+   -   *   /   %   ^   &amp;   |   &lt;<   &gt;> 
+=  -=  *=  /=  %=  ^=  &amp;=  |=  &lt;<=  &gt;>=  =
==  !=  &lt;   &gt;   &lt;=  &gt;=  &amp;&  ||  ,    .*   ->*

fold-operator>>=也是如此。

[expr.prim.fold]/2

形式where is a fold-operator的表达式称为一元左折叠。形式的表达式where is a fold-operator称为一元右折叠。一元左折叠和一元右折叠统称为一元折叠。在一元折叠中, 强制转换表达式应包含未扩展的包 ([temp.variadic])。(... op e)op(e op ...)op

(enums >>= ...)一元右弃牌也是如此。

[temp.variadic]/10

折叠表达式的实例化产生:

  • [...]

  • E1 op (⋯ op (EN−1 op EN))对于一元右折叠,

  • [...]

在每种情况下,opfold-operatorN是包扩展参数中的元素数量,每个 都是通过实例化模式并将每个包扩展参数替换为其 第 th 个元素而生成的。[...]Eii

因此,(enums >>= ...)在语义上等同于(A >>= (B >>= C))实例化它。所以这是 Clang 中的一个错误。

于 2019-07-11T00:24:16.437 回答