A resolução de sobrecarga ocorre apenas quando (a) você está chamando o nome de uma função / operador ou (b) está convertendo-o em um ponteiro (para função ou função membro) com uma assinatura explícita.
Nem está ocorrendo aqui.
std::function
pega qualquer objeto que seja compatível com sua assinatura. Não é necessário um ponteiro de função especificamente. (uma lambda não é uma função std e uma função std não é uma lambda)
Agora, nas minhas variantes de função de homebrew, para assinatura R(Args...)
, também aceito umR(*)(Args...)
argumento (uma correspondência exata) exatamente por esse motivo. Mas isso significa que eleva as assinaturas de "correspondência exata" acima das assinaturas "compatíveis".
O principal problema é que um conjunto de sobrecarga não é um objeto C ++. Você pode nomear um conjunto de sobrecarga, mas não pode transmiti-lo "nativamente".
Agora, você pode criar um conjunto de pseudo-sobrecarga de uma função como esta:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define OVERLOADS_OF(...) \
[](auto&&...args) \
RETURNS( __VA_ARGS__(decltype(args)(args)...) )
isso cria um único objeto C ++ que pode sobrecarregar a resolução em um nome de função.
Expandindo as macros, obtemos:
[](auto&&...args)
noexcept(noexcept( baz(decltype(args)(args)...) ) )
-> decltype( baz(decltype(args)(args)...) )
{ return baz(decltype(args)(args)...); }
o que é chato escrever. Uma versão mais simples, apenas um pouco menos útil, está aqui:
[](auto&&...args)->decltype(auto)
{ return baz(decltype(args)(args)...); }
temos uma lambda que aceita qualquer número de argumentos e, em seguida, os encaminha para a perfeição baz
.
Então:
class Bar {
std::function<void()> bazFn;
public:
Bar(std::function<void()> fun = OVERLOADS_OF(baz)) : bazFn(fun){}
};
trabalho. Adiamos a resolução de sobrecarga para o lambda em que armazenamos fun
, em vez de passarfun
diretamente um conjunto de sobrecargas (que não pode ser resolvido).
Houve pelo menos uma proposta para definir uma operação na linguagem C ++ que converte um nome de função em um objeto de conjunto de sobrecarga. Até que uma proposta desse padrão esteja no padrão, a OVERLOADS_OF
macro é útil.
Você poderia dar um passo adiante e oferecer suporte ao ponteiro de função de conversão para compatível.
struct baz_overloads {
template<class...Ts>
auto operator()(Ts&&...ts)const
RETURNS( baz(std::forward<Ts>(ts)...) );
template<class R, class...Args>
using fptr = R(*)(Args...);
//TODO: SFINAE-friendly support
template<class R, class...Ts>
operator fptr<R,Ts...>() const {
return [](Ts...ts)->R { return baz(std::forward<Ts>(ts)...); };
}
};
mas isso está começando a ficar obtuso.
Exemplo ao vivo .
#define OVERLOADS_T(...) \
struct { \
template<class...Ts> \
auto operator()(Ts&&...ts)const \
RETURNS( __VA_ARGS__(std::forward<Ts>(ts)...) ); \
\
template<class R, class...Args> \
using fptr = R(*)(Args...); \
\
template<class R, class...Ts> \
operator fptr<R,Ts...>() const { \
return [](Ts...ts)->R { return __VA_ARGS__(std::forward<Ts>(ts)...); }; \
} \
}