Это должно привести вас на полпути. Он компилируется с Visual C ++ 2010 и g ++ 4.5.1 с использованием Boost 1.46.0. Он не компилируется с реализацией Visual C ++ 2010 C ++ 0x <functional>
; Я еще не уверен, почему.
Настройка:
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
#include <boost/bind.hpp>
#include <boost/function.hpp>
// This helper allows you to do a push_back in a bind; you can't bind
// directly to std::vector::push_back because the type of a Standard
// Library member function is unspecified.
struct do_push_back
{
typedef void result_type;
template <typename TSequence, typename TElement>
void operator()(TSequence* sequence, const TElement& element) const
{
sequence->push_back(element);
}
};
Демонстрация:
// Class hierarchy for demonstration:
struct B { };
struct D : B { };
// Instead of using overlodaed nonmember functions, you can overload
// operator() in a function object. This allows you to bind to an
// instance of this function object, not directly to one of the overloads.
struct make_string
{
typedef std::string result_type;
std::string operator()(const B&) const { return "B"; }
std::string operator()(const D&) const { return "D"; }
};
int main()
{
std::vector<std::string> strings;
// Note that we do not use a boost::function here:
auto f = boost::bind(do_push_back(),
&strings,
boost::bind(make_string(), _1));
// Call our 'f' with B and D objects:
f(B());
f(D());
std::copy(strings.begin(), strings.end(),
std::ostream_iterator<std::string>(std::cout));
}
Результат:
BD
Вот почему это только половина решения: вы не можете сохранить результат вызова на boost::bind
в boost::function
. Проблема в том, что когда вы используете boost::function<void(const B&)>
для хранения объекта связанной функции, он всегда будет передавать const A&
в качестве аргумента связанной функции.
Даже если вы вызываете объект boost::function
с аргументом D
, он преобразуется в const B&
. Большая часть информации о типах теряется при использовании boost::function
; эта потеря информации о типе необходима, чтобы сделать boost::function
пригодным для использования в качестве универсального контейнера вызываемого объекта.
Это не значит, что вы не можете передать объект связанной функции; вам просто нужно использовать шаблоны, чтобы предотвратить потерю информации о типе:
template <typename TFunction>
void test(std::vector<std::string>& strings, TFunction f)
{
f(B());
f(D());
}
// In main():
test(strings, f);
// Or, if you don't have C++0x's "auto", you can pass the bound
// function object directly:
test(strings, boost::bind(do_push_back(),
&strings,
boost::bind(make_string(), _1)));
К сожалению, чтобы не потерять информацию о типе, вы должны передать связанный функциональный объект в шаблон функции. Это означает, что ваша идея сделать acceptVisitor
виртуальной функцией-членом не будет работать с этим решением (невозможно иметь шаблон виртуальной функции).
В любом случае, надеюсь, это поможет вам.