Почему оператор() функтора stateless не статичен?

Почему operator() функтора без сохранения состояния не может быть static? Лямбда-объекты без сохранения состояния можно преобразовать в указатели на свободные функции, имеющие ту же сигнатуру, что и их operator().

Стефан Т. Лававей на р. 6 указывает, что преобразование в указатель на функцию - это просто operator FunctionPointer() (cite). Но я не могу получить соответствующий указатель на operator() относительно функции, не являющейся членом. Для функторной struct F { void operator()() {} } кажется невозможным преобразовать &F::operator() в экземпляр типа, using P = void (*)(); ,

Код:

struct L
{
    static
    void operator () () const {} 
    operator auto () const
    { 
        return &L::operator ();
    }
};

Ошибка

перегруженный оператор() не может быть статической функцией-членом

но operator() не перегружен.

Ответ 1

В стандарте 13.5/6,

Операторная функция должна быть либо нестатической функцией-членом, либо быть не-членной функцией и иметь по крайней мере один параметр, тип которого является классом, ссылка на класс, перечисление или ссылка на перечисление.

Кроме того, в 13.5.4 говорится, что

оператор() должна быть нестатической функцией-членом с произвольным числом параметров. Он может иметь аргументы по умолчанию. Он реализует синтаксис вызова функции постфикс-выражение ( список_выражений выбирать ) где постфикс-выражение оценивает объект класса и возможно пустую список_выражений Матчи список параметров Оператор() член функции класса. Таким образом, вызов х (arg1,...) интерпретируется в виде x.operator() (arg1,...) для объекта класса Икс типа Т

Ответ 2

Я думаю, что нет никаких технических причин, чтобы запретить это (но, будучи не знакомым с де-факто кросс-вендором C++ ABI (Itanium ABI), я ничего не могу обещать).

Однако, существует эволюционная проблема по этому поводу на https://cplusplus.github.io/EWG/ewg-active.html#88. На нем даже есть [крошечная] отметка, что делает ее несколько "тривиальной" рассматриваемой особенностью.

Ответ 3

Я не вижу никаких технических причин, чтобы запретить static auto operator()( ... ). Но это особый случай, так что это усложнит стандарт, чтобы добавить поддержку для него. И такое усложнение не требуется, потому что очень легко подражать:

struct L
{
    static void func() {}

    void operator()() const { func(); }

    operator auto () const
    { 
        return &L::func;
    }
};

См. ответ Йоханнеса для некоторой, возможно, полезной дополнительной информации.

Ответ 4

Простой, немного грязный обходной путь, пока соответствующий комитет не рассмотрит эту тривиальную функцию:

Операторы glob синтаксически похожи на конструкторы.

Таким образом, вы не можете написать

static MyClass::operator()(...);

Это было сделано просто невозможно, потому что комитет принял решение по непонятным причинам. Я был бы так счастлив, если бы мог поговорить с одним из их членов, спросить, что было у них в голове, когда они так решили. К сожалению, он, вероятно, не поймет мой вопрос, потому что он никогда не программировал С++. Он работал только над своими документами.

Теперь им нужно несколько десятилетий

  • дебаты
  • консультации
  • встречи
  • и соображения

для реализации тривиальной функции. Я подозреваю, что эта функция может быть доступна в С++ 3x, а на эмулированных машинах она может быть даже опробована.

До тех пор вы можете попытаться написать:

MyClass::MyClass(...);

В обоих случаях вы можете вызвать MyClass(...);.

Конечно, это полезно, главным образом, если MyClass является одноэлементным. И, я бы сказал, это взломать. Кроме того, он выделяет sizeof(MyClass) в стеке, который может быть плохим с точки зрения производительности/эффективности.


Кроме того, это будет по существу конструктором, а конструкторы ничего не могут вернуть. Но вы можете избежать этого, сохранив результат в экземпляре, а затем отбросив его оператором трансляции на все, что хотите.

Ответ 5

Как и другие, я не вижу фундаментальной причины, почему это невозможно.

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

struct A{
  void f();
  static int f(); // compile error 
}

Таким образом, даже если бы было разрешено иметь static operator(), это должно быть разрешено?

struct A{
  void operator()();
  static int operator()(); // should be a compiler error??? 
}

В любом случае, есть только одна истинная причина иметь static operator() который не является чисто синтаксической причиной, и что объекты должны иметь возможность вызывать статические функции, как если бы они были функциями-членами.

struct A{
   static int f():
}
...
A a; 
a.f(); // calls A::f() !!!

В частности, пользователю класса A не нужно знать, реализована ли функция как статическая или как член. Позднее его можно обновить до функции-члена с общей точки зрения.

Если оставить в стороне это важное приложение для общего программирования, то есть обходной путь, ведущий к аналогичному синтаксису, который я видел в https://quuxplusone.github.io/blog/2018/03/19/customization-points-for-functions/, и это должно иметь статическую функцию-член с именем _, имя, которое не подразумевает никакого значения.

struct A{
    static int _();
}
...
A::_(); // instead of the more desirable (?) A::() or A::operator()
a._(); // this invokes the static functon _ 

Вместо более желательного A::() или A::operator(), (ну, они вообще желательны? Я не знаю; что-то вроде A() было бы действительно интересно, но даже не следовало синтаксису статическая функция и может быть перепутана с конструктором).

(Как я уже сказал, единственная особенность, которую я все еще упускаю из-за этого ограничения, на которое вы указали, - это то, что a() не может автоматически делегироваться статической версии operator(), например, A::operator().)

В итоге ваш код может выглядеть так:

struct L{
    static void _() const {} 
    operator auto () const{ 
        return &L::_();
    }
};

Не уверен, что готовы достичь еще.