Void (), оператор запятой (operator,) и невозможная (?) Перегрузка

Рассмотрим следующую структуру:

struct S {};

В C ++ 14 приведенное ниже определение является действительным:

constexpr auto f() { return S{}, 'c'; }

А также следующий:

constexpr auto f() { return S{}, void(); }

Теперь рассмотрим следующий рабочий фрагмент, включающий первое из двух определений:

#include<type_traits>

struct S {};

constexpr int operator,(S, char) { return 42; }
constexpr auto f() { return S{}, 'c'; }

int main() {
constexpr int i{f()};
static_assert(i == 42, "!");
static_assert(std::is_same<decltype(f()), int>::value, "!");
}

Если говорить не так технически, то перегрузка оператора запятой перехватывает пара S{}, 'c' и возвращает целое число, как правильно проверено в main функция.

Теперь предположим, что я хочу сделать то же самое со вторым определением f:

constexpr auto f() { return S{}, void(); }

В этом случае оператор запятой должен перехват форма S{}, void(),
Ни одно из следующих определений не работает (по понятным причинам):

constexpr int operator,(S, void) { return 42; }

Ни один из приведенных ниже (это сработало бы в предыдущем случае):

template<typename T> constexpr int operator,(S, T &&) { return 42; }

Есть ли способ перегрузить оператор запятой, чтобы иметь дело с S{}, void()?
Разве это не недостаток в стандарте, поскольку он позволяет использовать оператор запятой таким образом, но не дает возможности перегрузить тот же оператор (даже если стандарт упоминает, что перегруженные функции с участием S разрешены)?


Заметка: этот вопрос сделан ради любопытства. Пожалуйста, избегайте комментариев, таких как не делай этого или же это не очень хорошая практика. Я не планирую делать это в производственных условиях. Спасибо.

17

Решение

Соответствующее условие для этого — 13.3.1.2/9 [over.match.oper] в N4140:

Если оператор является оператором ,, унарный оператор &или оператор ->и нет жизнеспособных функций,
тогда оператор считается встроенным оператором и интерпретируется в соответствии с разделом 5.

Как void() никогда не является допустимым аргументом функции (см. 5.2.2 / 7 [expr.call]), никогда не бывает жизнеспособной функции и, следовательно, встроенной , будет использоваться.

Так что нет, то, что вы пытаетесь сделать, невозможно.

На самом деле, написание цикла итератора, как это

for(...; ++it1, (void)++it2)

это стандартный способ предотвратить взлом вашего кода пользователями из-за перегрузки , для их типов итераторов, применяя встроенный оператор , использоваться. (Обратите внимание, что я не говорю, что вы должны делать это в своем повседневном коде. Это очень сильно зависит от его фактического использования. Это стандартный уровень библиотеки для параноиков.)


Относительно стандартного предложения вы связали:

Смысл операторов =, (унарный) &и (запятая), предварительно определенные для каждого типа, могут быть изменены для определенного класса и типов перечисления путем определения операторских функций, которые реализуют эти операторы.

Но такую ​​функцию нельзя определить, потому что, как я сказал выше, void() никогда не является допустимым аргументом функции.

Теперь, является ли это упущением / проблемой в стандарте, открыто для обсуждения.

23

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector