Почему в C 23 std::move_only_function нет руководств по дедукции?

#c #c 17 #std-function #c 23

Вопрос:

C 23 представил std::function двоюродного std::move_only_function брата , как и его название, это оболочка только для перемещения для вызываемых объектов, доступных только для перемещения (демо).:

 #include <functional>
#include <memory>

int main() {
  auto l = [p = std::make_unique<int>(0)] { };
  std::function<void(void)>           f1{std::move(l)}; // ill-formed
  std::move_only_function<void(void)> f2{std::move(l)}; // well-formed
}
 

Но в отличие std::function от этого , стандарт не определяет для него руководства по вычету (демонстрационное):

 #include <functional>

int func(double) { return 0; }
int main() {
  std::function f1{func};           // guide deduces function<int(double)>
  std::move_only_function f2{func}; // deduction failed
}
 

Есть ли причина для запрета CTAD?

Комментарии:

1. Нет необходимости подозревать, голосование по CTAD уже состоялось open-std.org/jtc1/sc22/wg21/docs/papers/2021/… — 1 за против 9 против.

2. вы можете спросить авторов статьи, например, в Twitter @ CppSage и @ sempuki1 или по адресам электронной почты, указанным в статье

3. Сайт проводника компилятора называется Godbolt, а не Goldbot; он назван в честь Мэтта Годболта.

Ответ №1:

Подобные обертки для стирания типов move_only_function предназначены для использования на границах API, где типы являются явными, что делает CTAD для них сомнительной полезностью.

Любой CTAD для этих вызываемых оболочек в любом случае должен быть довольно ограниченным — он не может обрабатывать перегруженные функции или шаблоны функций, что также означает, что он не может обрабатывать общие лямбды, что является довольно существенным ограничением его полезности. std::function CTAD также поставляется с оговоркой о том, что более поздние стандарты могут изменить выводимый тип (мы его еще не изменили, но и не удалили оговорку).

И при move_only_function этом выводятся не только типы возвращаемых данных и аргументов. const , noexcept , и ref-квалификаторы все в игре, и это создает новые проблемы с дизайном. Например, выводит ли вывод из int (*)(int) вывода int(int) ? Почему бы и нет int(int) const — указатели функций, в конце концов, можно вызывать постоянно?

И если CTAD окажется необходимым — и кто — то придумает для него хороший дизайн-его всегда можно добавить позже.

Я не знаю, все ли эти вопросы были затронуты в обсуждении LEWG (протоколы довольно скудны), но я думаю, что их более чем достаточно, чтобы оправдать отказ от поддержки CTAD.

Комментарии:

1.Если есть свободная функция void foo() , я думаю move_only_function , что ее можно вывести void() так std::function же, как и раньше, поскольку она явно интуитивно понятна. И мы все еще можем назначить его вызываемому объекту, у которого есть void operator() или void operator() const . Когда вызываемый объект имеет и const const то, и другое, и неквалифицированный оператор (), вызов последнего также кажется более интуитивным выбором, потому что мы выводим тип через свободную функцию. Если мы хотим позвонить operator() const , мы должны void() const явно указать в начале.

2. Дело в том, что ответы не совсем очевидны (с другой стороны, делает []{} вывод void() const ?). Обычно для этого нужно было бы рассмотреть реальные варианты использования — за исключением того, что для move_only_function CTAD существует не так много вариантов использования, с которых можно начать.

3. «делает []{} вывод void() const ?» Абсолютно. Так же, как [] noexcept {} и выводится void() const noexcept . С введением вывода об этом ситуация будет становиться все более и более сложной, но я все еще с нетерпением жду того дня, когда CTAD будет восстановлен, хотя это кажется очень далеким. 😉