В последнее время я написал шаблонную функцию для решения некоторых повторений кода. Это выглядит так:
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);
}
Этот код прекрасно работает, для class A
которого выглядит так:
class A {
public:
void foo(int x) {
}
};
Но не может скомпилировать для одного, как это:
class A {
public:
void foo(const int& x) {
}
};
Почему это так (почему я имею в виду, почему он не может определить тип) и как (если это вообще возможно) заставить этот код работать со ссылками? Живой пример
Args&&...
иstd::forward
?Ответы:
Ваша проблема заключается в том, что у вас есть конфликтные выводы
Args
между:R (T::*fun)(Args...)
Args... args
Я предлагаю , чтобы иметь больше общий код (отсутствие дублирования между
R (T::*fun)(Args...)
иверсией сопзЬ
R (T::*fun)(Args...) const
и другой альтернативой) с:источник
Args
типы не могут быть выведены какconst&
(изfun
объявления параметра), так и без ссылки изargs
объявления. Простым решением является использование двух отдельных пакетов параметров типа шаблона:Как недостаток, я могу представить немного более длинные сообщения об ошибках в случае неправильного использования.
источник
Args&&... args
Обратите внимание, что
Args
тип параметра шаблона выводится какconst int&
на 3-м аргументе функции&A::foo
, так иint
на 4-м параметре функции1
. Они не совпадают и вызывают сбой дедукции.Вы можете исключить 4-й параметр из вычета , например,
ЖИТЬ
PS:
std::type_identity
поддерживается начиная с C ++ 20; но это довольно легко реализовать.источник
Args&&...
Затем добавитьstd::type_identity
3-й параметр какR (T::*fun)(std::type_identity_t<Args>...)
. Прямой и Прямой