Я пытаюсь написать код, который вызывает метод класса, заданный как параметр шаблона. Чтобы упростить, вы можете предположить, что метод имеет единственный параметр (произвольного типа) и возвращает void. Цель состоит в том, чтобы избежать шаблона в вызывающем сайте, не набрав тип параметра. Вот пример кода:Как передать указатель метода в качестве параметра шаблона
template <class Method> class WrapMethod {
public:
template <class Object>
Param* getParam() { return ¶m_; }
Run(Object* obj) { (object->*method_)(param_); }
private:
typedef typename boost::mpl::at_c<boost::function_types::parameter_types<Method>, 1>::type Param;
Method method_;
Param param_
};
Сейчас на сайте вызова, я могу использовать метод никогда не писать тип параметра.
Foo foo;
WrapMethod<BOOST_TYPEOF(&Foo::Bar)> foo_bar;
foo_bar.GetParam()->FillWithSomething();
foo_bar.Run(foo);
Таким образом, этот код работает, и это почти то, что я хочу. Единственная проблема заключается в том, что я хочу избавиться от макрокоманды BOOST_TYPEOF на вызывающем сайте. Я хотел был бы написать что-то вроде WrapMethod<Foo::Bar> foo_bar
вместо WrapMethod<BOOST_TYPEOF(&Foo::Bar)> foo_bar
.
Я подозреваю, что это невозможно, так как нет способа ссылаться на подпись метода, отличную от использования самой подписи метода (которая является переменной для WrapMethod и что-то довольно большое для ввода на вызывающем сайте) или получения указатель метода, а затем выполните typeof.
Любые подсказки о том, как исправить эти или различные подходы к тому, как избежать ввода типа параметра на вызывающем сайте, оцениваются.
Для уточнения моих потребностей: решение не должно иметь имя типа Param в вызывающем сайте. Кроме того, он не может вызывать FillWithSomething из WrapMethod (или аналогичного). Поскольку имя этого метода может изменяться от типа Param до типа Param, оно должно проживать на вызывающем сайте. Решение, которое я дал, удовлетворяет обоим этим ограничениям, но нуждается в уродливом BOOST_TYPEOF в вызывающем сайте (использование его внутри WrapMethod или другой косвенности было бы хорошо, так как это код, который мои пользователи api не будут видеть, пока это будет правильно).
Ответ:
Насколько я могу сказать, что нет возможных решений. Это сводится к тому, что невозможно написать что-то вроде WrapMethod<&Foo::Bar>
, если подпись Бар не известна заранее, хотя требуется только мощность. В более общем плане вы не можете иметь параметры шаблона, которые принимают значения (а не типы), если тип не фиксирован. Например, невозможно написать что-то вроде typeof_literal<0>::type
, которое вычисляет int
и typeof_literal<&Foo::Bar>::type
, что в моем примере будет оцениваться void (Foo*::)(Param)
. Обратите внимание, что ни BOOST_TYPEOF, ни declype не помогли бы, потому что они должны были жить на сайте катания и не могли быть заглублены глубже в коде. Легитимный, но недопустимый синтаксис ниже будет решить эту проблему:
template <template<class T> T value> struct typeof_literal {
typedef decltype(T) type;
};
В C++ 0x, как указано в выбранной реакцию (и в других, используя BOOST_AUTO), можно использовать автоматическое ключевое слово для достижения тех же целей в другим способом:
template <class T> WrapMethod<T> GetWrapMethod(T) { return WrapMethod<T>(); }
auto foo_bar = GetWrapMethod(&Foo::Bar);
Это работает, но BOOST_TYPEOF - тип decltype одинаковый (почти). Использование их в WrapMethod выполняется нормально, но не на вызывающем сайте. – Davi
Справа. Думаю, у вашего отредактированного ответа есть почти все варианты. Итак, с C++ 03 я застрял, и с C++ 0X я мог использовать decltype вместо BOOT_TYPEOF, или я мог бы использовать автоматическое решение, что довольно приятно. – Davi