Я пытаюсь написать код, который вызывает метод класса, заданный в качестве параметра шаблона. Для упрощения можно предположить, что метод имеет единственный параметр (произвольного типа) и возвращает 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, ни decltype не помогут, потому что они должны жить в месте вызова и не могут быть углублены в код. Допустимый, но неверный синтаксис, приведенный ниже, решит проблему:
template <template<class T> T value> struct typeof_literal {
typedef decltype(T) type;
};
В C ++ 0x, как указано в выбранном ответе (и в других, использующих BOOST_AUTO), можно использовать ключевое слово auto для достижения той же цели другим способом:
template <class T> WrapMethod<T> GetWrapMethod(T) { return WrapMethod<T>(); }
auto foo_bar = GetWrapMethod(&Foo::Bar);