Ultimamente, escrevi uma função de modelo para resolver algumas repetições de código. Se parece com isso:
template<class T, class R, class... Args>
R call_or_throw(const std::weak_ptr<T>& ptr, const std::string& error, R (T::*fun)(Args...), Args... args) {
if (auto sp = ptr.lock())
{
return std::invoke(fun, *sp, args...);
}
else
{
throw std::runtime_error(error.c_str());
}
}
int main() {
auto a = std::make_shared<A>();
call_or_throw(std::weak_ptr<A>(a), "err", &A::foo, 1);
}
Este código funciona perfeitamente bem para o class A
qual se parece com isso:
class A {
public:
void foo(int x) {
}
};
Mas falha ao compilar para um como este:
class A {
public:
void foo(const int& x) {
}
};
Por que é assim (por que quero dizer por que não deduz o tipo) e como (se é possível) posso fazer esse código funcionar com referências? Exemplo ao vivo
Args&&...
estd::forward
?Respostas:
Seu problema é que você tem deduções de conflito
Args
entre:R (T::*fun)(Args...)
Args... args
Sugiro ter um código mais genérico (sem duplicações entre
R (T::*fun)(Args...)
eversão const
R (T::*fun)(Args...) const
e outra alternativa) com:fonte
Args
tipos não podem ser deduzidos comoconst&
(dafun
declaração de parâmetro) e não referência daargs
declaração. Uma correção simples é usar dois pacotes de parâmetros de tipo de modelo separados:Como desvantagem, posso imaginar mensagens de erro um pouco mais longas em caso de mau uso.
fonte
Args&&... args
Observe que o
Args
tipo de parâmetro do modelo é deduzido comoconst int&
no argumento da 3ª função&A::foo
e deduzido comoint
no parâmetro da 4ª função1
. Eles não coincidem e causam falhas na dedução.Você pode excluir o quarto parâmetro da dedução , por exemplo
VIVER
PS:
std::type_identity
é suportado desde C ++ 20; mas é muito fácil implementar um.fonte
Args&&...
, coloquestd::type_identity
o terceiro parâmetro comoR (T::*fun)(std::type_identity_t<Args>...)
. LIVE and LIVE