Здравствуйте, c_beginner, Вы писали:
_>Рассматривал как вариант, но проблемки следующего плана. В any придется хранить ссылку на переменную, скажем, boost::reference_wrapper<T>.
Я невнимательно прочитал задание. Действительно, мороки много будет.
_>Каким образом я могу определить тип, который удерживает boost::any — используя boost::any_cast, для всех возможных типов переменных контейнера, а это — не решение.
Перебирать не обязательно, см. пример ниже. Можно заглянуть в файл «boost/any.hpp» и действовать по аналогии. Кстати, ваша реализация так же хороша, как и в Бусте. Только они дополнительно спрятали классы реализации (вашим классам AbstractProperty и Property<> соответствуют бустовские placeholder и holder<>). Т. е. вы могли бы скрыть от класса VariableContainer абстрактный и шаблонный классы, предоставив самый обычный. При этом улучшилась бы инкапсуляция, но раздулся бы код. Так что ваш вариант всё таки лучше, чем мой:
#include <boost/any.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/ref.hpp>
#include <cassert>
#include <iostream>
#include <string>
#include <hash_map>
#include <utility>
class Property
{
private:
class Placeholder {
public:
virtual void Set(boost::any a, std::string const& value) const = 0;
virtual ~Placeholder() {}
};
template <typename T> class Holder : public Placeholder {
public:
void Set(boost::any a, std::string const& value) const {
T::type& ref( boost::any_cast<T>(a) );
ref = boost::lexical_cast<T::type>(value);
}
};
public:
Property() : setter_() {}
template <typename T> Property(T const& value) : setter_(new Holder<T>), a_(value) {}
void Set(std::string const& value) { if (setter_) { setter_->Set(a_, value); } }
private:
boost::any a_;
boost::shared_ptr<Placeholder> setter_;
};
class VariableContainer
{
public:
template <typename T>
void Register(std::string const& name, T& var)
{
map_.insert( std::make_pair(name, boost::ref(var)) );
}
void Set(const std::string &name, const std::string &value)
{
map_[name].Set(value);
}
private:
stdext::hash_map<std::string, Property> map_;
};
int main()
{
VariableContainer c;
int i(0);
std::string str("");
c.Register("int", i);
c.Register("str", str);
c.Set("int", "12");
c.Set("str", "hello");
std::cout << i << std::endl;
std::cout << str << std::endl;
assert(i == 12);
assert(str == "hello");
return 0;
}
_>virtual ~AbstractProperty() = 0 {};
Оказывается, это нестандартно: «A function declaration cannot provide both a pure-specifier and a definition», пункт 10.4.2. Т. е. определение чисто-виртуальной функции должно быть вынесено из объявления класса. Но все компиляторы такой код поддерживают, потому синтаксическому анализатору это вовсе не сложно, так что я тоже изредка забиваю на Стандарт.