#c
#c
Вопрос:
Предположим, у нас есть шаблон класса, подобный этому:
template <typename baseT, typename ...argTs>
class CCallable : public baseT
{
public:
CCallable(std::function<bool(argTs...)> lambda)
: m_lambda(lambda) {
}
bool Invoke(argTs ...args) override {
return m_lambda(args...);
}
private:
std::function<bool(argTs...)> m_lambda;
};
И предположим, что у нас callback
реализован шаблон функции, вероятно, похожий на этот псевдокод:
template <typename baseT, typename lambdaT>
CCallable<baseT, typename lambdaT::argTs...> callback(lambdaT lambda)
{
return CCallable<baseT, typename lambdaT::argTs...>(lambda);
}
чтобы мы могли это сделать:
autoamp;amp; functor = callback<CBase>([](int x, int y, int *sum)->bool{
*sum = x y;
return true;
});
// Start passing functor around and then...
int sum;
functor.Invoke(7, 42, amp;sum);
Пожалуйста, обратите внимание, что типы параметров лямбда-выражения не передаются в callback
качестве аргументов его типа шаблона.
Как мы можем реализовать шаблон функции, подобный этому, чтобы избавить пользователей от ввода большего количества кодов, таких как:
autoamp;amp; functor = callback<CBase, int, int, int*>([](int x, int y, int *sum)->bool{
*sum = x y;
return true;
});
Спасибо.
Кстати, почему я спрашиваю об этом, потому Microsoft::WRL
что предоставляет аналогичный шаблон с именем Callback
, который вызывается много раз в библиотеке с открытым исходным кодом, которую я хочу использовать. Однако я предпочитаю создавать библиотеку с помощью GNU C вместо Visual C . Поэтому кажется неизбежным, что мне придется самому реализовать Microsoft::WRL::Callback
подобный шаблон или макрос.
Комментарии:
1. Помните, что лямбда-выражение может вызываться с несколькими типами… (Например, автоматический параметр im c 14)
2. В документе это выглядит так, что необходимо указать параметр шаблона, нет?
3. Вы могли бы создать
Invoke()
сам шаблон.4. @user202729 У него должен быть аргумент типа шаблона, но единственным обязательным параметром типа является базовый класс, а не какие-либо типы в списке параметров лямбда, которому передается
Callback
. ВозможноCallbak
, он получает эти типы из базового класса idk.5. @G.Sliepen Нет, шаблону метода не разрешается быть виртуальным. Смотрите ключевое
override
слово там после списка параметровInvoke
?
Ответ №1:
С C 17 CTAD вы можете использовать руководства по вычету для std::function
:
template<class T>
struct Identity { };
template<typename baseT, typename ...argTs>
class CCallable : public baseT {
public:
CCallable(std::function<bool(argTs...)> lambda, Identity<baseT> = {})
: m_lambda(lambda) {
}
bool Invoke(argTs ...args) override {
return m_lambda(args...);
}
private:
std::function<bool(argTs...)> m_lambda;
};
template<typename baseT, typename lambdaT>
auto callback(lambdaT lambda) {
return CCallable(std::function(lambda), Identity<baseT>{});
}
CTAD — это все или ничего, поэтому тип baseT
заключен в Identity
, чтобы сделать его выводимым.
Комментарии:
1. Я думаю, что на земле, отличной от C 17, это в основном так
template<typename B, typename F, typename G, typename R, typename... As> CCallback<B, As...> callback_impl(F amp;f, R (G::*)(As...)) { return CCallable<B, As...>(f); } template<typename B, typename F> auto callback(F f) /* -> decltype(callback_impl<B>(f, amp;F::operator())) */ { return callback_impl<B>(f, amp;F::operator()); }
(в этом нет необходимостиIdentity
). Я на самом деле не понимал, что стандартная библиотека санкционировала это! Я всегда думал, что это немного взлом,2. @HTNW Спасибо. Ваш код работает отлично, даже если аргументом
callback
является лямбда, аstd::function<>
не объект. AFAIK, компиляторы не выполняют неявное преобразование для аргументов шаблонов функций, но в этом случае похоже, что лямбда неявно преобразуется в astd::function<>
. Почему? Что произошло? Я в замешательстве.3. @Cody Неявное преобразование подавляется только во время вывода аргумента шаблона, потому что мы можем не знать тип, в который нам нужно преобразовать (поскольку мы еще не вывели параметры шаблона). Если мы задали достаточно аргументов шаблона, чтобы узнать тип параметра, неявное преобразование может продолжаться как обычно.
4. @HTNW Позвольте мне прояснить это для людей, которые, возможно, ищут решение той же проблемы. Если использовать
nm
илиobjdump
для проверки символов, сгенерированных 2 шаблонами функций, упомянутыми выше, нет никаких доказательств того, что при передаче аргументов в шаблоны функций происходило неявное преобразование. Лямбда-выражение по-прежнему остается лямбдой.std::function<>
Объект создаетсяcallback_impl
послеcallback_impl
получения типов аргументов лямбда-аргумента изcallback
.