Ostatnio napisałem funkcję szablonu, aby rozwiązać niektóre powtórzenia kodu. To wygląda tak:
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);
}
Ten kod działa doskonale, dla class A
którego wygląda tak:
class A {
public:
void foo(int x) {
}
};
Ale nie można skompilować dla takiego:
class A {
public:
void foo(const int& x) {
}
};
Dlaczego tak jest (dlaczego mam na myśli, dlaczego nie można wydedukować typu) i jak (jeśli w ogóle jest to możliwe) mogę sprawić, aby ten kod działał z referencjami? Przykład na żywo
Args&&...
istd::forward
?Odpowiedzi:
Problem polega na tym, że masz potrącenia konfliktowe
Args
między:R (T::*fun)(Args...)
Args... args
Proponuję mieć kod bardziej ogólny (bez powielania pomiędzy
R (T::*fun)(Args...)
iwersji const
R (T::*fun)(Args...) const
i inne alternatywy) z:źródło
Args
typów nie można wywnioskować zarówno jakoconst&
(zfun
deklaracji parametrów), jak i bez odniesienia zargs
deklaracji. Prostą poprawką jest użycie dwóch oddzielnych pakietów parametrów typu szablonu:Jako wadę mogę sobie wyobrazić nieco dłuższe komunikaty o błędach w przypadku złego użytkowania.
źródło
Args&&... args
Zauważ, że
Args
typ parametru szablonu jest wywnioskowany jakconst int&
w argumencie 3. funkcji&A::foo
i wywnioskowany jakint
w parametrze 4. funkcji1
. Nie pasują i powodują, że dedukcja nie udaje się.Możesz wykluczyć czwarty parametr z odliczenia , np
RELACJA NA ŻYWO
PS:
std::type_identity
jest obsługiwany od C ++ 20; ale bardzo łatwo go wdrożyć.źródło
Args&&...
Następnie ustawićstd::type_identity
trzeci parametr jakR (T::*fun)(std::type_identity_t<Args>...)
. NA ŻYWO i NA ŻYWO