Законно ли использовать оператор в выражении сгиба, которое было введено объявлением использования? - PullRequest
17 голосов
/ 05 июля 2019

Я экспериментировал с использованием произвольных функций в выражениях сгиба, когда нашел следующий код, который компилируется с gcc, но не компилируется с clang.

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?Или записанный эквивалент выражения сгиба не совсем эквивалентен?

1 Ответ

2 голосов
/ 11 июля 2019

За [expr.prim.fold] / фолд-оператор :

фолд-оператор: один из

+   -   *   /   %   ^   &   |   <<   >> 
+=  -=  *=  /=  %=  ^=  &=  |=  <<=  >>=  =
==  !=  <   >   <=  >=  &&  ||  ,    .*   ->*

Итак, >>= является оператором сгиба .

За [expr.prim.fold] / 2 :

Выражение вида (... <em>op</em> e), где op - это оператор сгиба называется унарным левым сгибом ,Выражение вида (e <em>op</em> ...), где op представляет собой оператор сгиба , называется унарным правым сгибом .Одинарные левые складки и одинарные правые складки в совокупности называются одинарными складками .В одинарном сгибе приведенное выражение должно содержать нерасширенную пачку ([temp.variadic]).

Так что (enums >>= ...) - унарный правый сгиб.

Per [temp.variadic] / 10 :

Создание складного выражения дает:

  • [...]

  • E<sub>1</sub> <em>op</em> (⋯ <em>op</em> (E<sub><em>N</em>−1</sub> <em>op</em> E<sub><em>N</em></sub>)) для одинарного правого сгиба,

  • [...]

В каждом случае op - это оператор сгиба , N - количество элементов вПараметры расширения пакета, и каждый E<sub><em>i</em></sub> создается путем создания экземпляра шаблона и замены каждого параметра расширения пакета своим элементом i th .[...]

Следовательно, (enums >>= ...) семантически эквивалентен (A >>= (B >>= C)) при его создании.Так что это ошибка в Clang.

...