C++26 fornece std::copyable_function
[cppref link] . No entanto, o existente std::function
já é copyable
. Então, tenho 3 perguntas:
Quais são as principais vantagens de
std::copyable_function
mais destd::function
?Invocar um vazio
std::copyable_function
é indefinido, enquanto invocar um vaziostd::function
lançará uma exceção. Qual é a lógica por trás disso?Foi
std::function
descontinuadostd::copyable_function
em C++26?
São dois.
Primeiro, não há
target()
API, o que geralmente não era super útil de qualquer maneira, então há menos sobrecarga porquestd::copyable_function
não é preciso rastrear algo questd::function
o fez. Mas isso é menor.O mais importante é a superfície da API.
std::function
Parece com isso:O operador de chamada (1) sempre
const
e (2) nuncanoexcept
. (1) é um problema porque você ainda pode invocar umaconst
função que não seja membro sem querer.std::copyable_function
parece com isso:O que significa que, por exemplo,
copyable_function<void(int)>
tem um operador não-const
, não-noexcept
call, mascopyable_function<void(int) const noexcept>
tem um que é ambosconst
enoexcept
. Tudo isso é especificável.Isso torna o uso claro e descritivo... e mais correto!
Pode-se argumentar que invocar um vazio
std::function
é um bug. Há muitas pessoas que acham que lançar para sinalizar erro do programador é uma maneira ruim de fazer isso - chamá-lo de comportamento indefinido significa que a implementação pode afirmar.A resposta literal para essa pergunta é: não. Mas talvez a pergunta mais interessante seja: deveria ter sido? À qual eu ainda responderia não.
Há uma quantidade muito grande de código que usa
std::function
e uma grande porcentagem dele provavelmente está correta. Também não é uma simples renomeação para transição, já que muitos usuários vão querer mudar defunction<R(Args...)>
paracopyable_function<R(Args...) const>
. Mas também muitos usuários vão querer mudar paramove_only_function<R(Args...) const>
em vez disso.Provavelmente é uma boa ideia realmente fazer essas mudanças (especialmente se você não precisa de
target()
, o que... ninguém precisa). Mas elas não são tão urgentes que você realmente queira um[[deprecated]]
aviso sobre isso. Parece mais uma sugestão discreta de modernização.Na verdade, há dois níveis aqui:
A
é ruim (possivelmente ativamente prejudicial),B
é estritamente superior, por favor troque.A
está bem,B
está melhor. PrefiraB
em código novo, masA
não é prejudicial.A transição de
auto_ptr<T>
paraunique_ptr<T>
se encaixa nessa primeira categoria. A transição defunction<R(Args..)>
paracopyable_function<R(Args...) const>
(oumove_only_function<R(Args...) const>
, ou às vezes atéfunction_ref<R(Args...) const>
) para mim é mais como a segunda categoria.A
está bom. Não grite comigo por ainda usá-lo em código antigo.