Это нежелательно в общем случае.(Обратите внимание, что для std::function<T(A)>
довольно просто указать, например, что такое argument_type
: это просто A
! Это доступно в определении типа.)
Можно потребовать каждый функциональный объектtype, чтобы указать типы аргументов, и, в свою очередь, предписывает, чтобы это делали типы замыкания, сгенерированные из лямбда-выражения.Фактически, функции до C ++ 0x, такие как адаптируемые функторы, работали бы только для таких типов.
Однако мы переходим к этому с C ++ 0x и по веским причинам.Самым простым из которых является просто перегрузка: тип функтора с шаблонным operator()
(он же полиморфный функтор) просто принимает все виды аргументов;так что же должно быть * 1009?Другая причина заключается в том, что универсальный код (обычно) пытается указать наименьшие ограничения на типы и объекты, с которыми он работает, чтобы его было легче (повторно) использовать.
Другими словами, универсальный код не является действительно интересует, что с учетом Functor f
, typename Functor::argument
будет int
. гораздо больше интересно знать, что f(0)
является приемлемым выражением.Для этого C ++ 0x предоставляет такие инструменты, как decltype
и std::declval
(удобно упаковывать их вместе внутри std::result_of
).
На мой взгляд, у вас есть два варианта: требовать, чтобы все функторы были переданываш шаблон использует соглашение в стиле C ++ 03, определяющее argument_type
и т.п .;используйте технику ниже;или перепроектировать.Я бы порекомендовал последний вариант, но это ваш вызов, так как я не знаю, как выглядит ваша кодовая база или каковы ваши требования.
Для мономорфного типа функтора (т.е. без перегрузки) этоможно осмотреть operator()
член.Это работает для типов закрытия лямбда-выражений.
Поэтому мы объявляем этих помощников
template<typename F, typename Ret, typename A, typename... Rest>
A
helper(Ret (F::*)(A, Rest...));
template<typename F, typename Ret, typename A, typename... Rest>
A
helper(Ret (F::*)(A, Rest...) const);
// volatile or lvalue/rvalue *this not required for lambdas (phew)
, которые принимают указатель на функцию-член, принимающую хотя бы один аргумент.А теперь:
template<typename F>
struct first_argument {
typedef decltype( helper(&F::operator()) ) type;
};
[сложная черта может последовательно запрашивать перегрузки lvalue-rvalue / const / volatile и выставлять первый аргумент, если он одинаков для всех перегрузок, или использовать std::common_type
.]