boost :: любая замена для кода ниже

Я хотел бы избавиться от буст-зависимости от моего кода. У меня есть следующая конструкция структуры. При вызове и использовании этой структуры в другом месте кода boost::any_cast используется. Я знаю, что шаблонный класс сделает это, но мне сложно написать этот шаблон. — C ++ Rookie.

 struct Properties {
public:
Properties() {}
Properties(const std::string &s, const boost::any & p) {
name = s;
value = p;
}

template <typename T>
Properties(T n) {
value = n;
}
boost::any value;

std::string name;
};

1

Решение

Просто ради интереса, я подумал, что создам минималистичную любую реализацию:

//////////////////////////////////////////
// my_any.hpp
#include <memory>
#include <stdexcept>

struct my_any
{
my_any() = default;
template <typename T> my_any(T const& v) : _storage(new storage<T>(v)) { }
my_any(my_any const& other)              : _storage(other._storage? std::move(other._storage->clone()) : nullptr) {}

void swap(my_any& other)               { _storage.swap(other._storage); }
friend void swap(my_any& a, my_any& b) { a.swap(b); };
my_any& operator=(my_any other)        { swap(other); return *this; }

// todo move semantics
private:
struct storage_base {
virtual std::unique_ptr<storage_base> clone() = 0;
virtual ~storage_base() = default;
};
template <typename T>
struct storage : storage_base {
T value;
explicit storage(T const& v) : value(v) {}
std::unique_ptr<storage_base> clone() { return std::unique_ptr<storage_base>(new storage<T>(value)); }
};
std::unique_ptr<storage_base> _storage;
template<typename T> friend T      & any_cast(my_any      &);
template<typename T> friend T const& any_cast(my_any const&);
};

template <typename T> T& any_cast(my_any& a) {
if (auto p = dynamic_cast<my_any::storage<T>*>(a._storage.get()))
return p->value;
else
throw std::bad_cast();
}

template <typename T> T const& any_cast(my_any const& a) {
if (auto p = dynamic_cast<my_any::storage<T> const*>(a._storage.get()))
return p->value;
else
throw std::bad_cast();
}

Затем вы можете использовать его точно так же, как показано в ваших сценариях использования:

struct Properties {
public:
Properties(const std::string &s="", const my_any& p={})
: name(s), value(p) {}

template <typename T> Properties(T n) { value = n; }

std::string name;
my_any value;
};

#include <vector>
#include <iostream>

typedef std::vector<Properties> Props;

int main()
{
Props v;
v.emplace_back("bye", 42);
v.emplace_back("vector", v);

std::cout << "v.size(): "          << v.size()                           << "\n";
std::cout << "v[0].value: "        << any_cast<int>(v[0].value)          << "\n";
std::cout << "v[1].value.size(): " << any_cast<Props>(v[1].value).size() << "\n";

v[0].value = v;

try {
std::cout << "v[0].value: " << any_cast<int>(v[0].value) << "\n";
} catch(std::exception const& e)
{
std::cout << e.what() << " exception caught, ok!\n";
}

std::cout << "v[0].value.size(): " << any_cast<Props>(v[0].value).size() << "\n";
}

Смотрите вывод Жить на Колиру

5

Другие решения

boost::any использует стирание типов для хранения объектов любого типа, и вы можете присваивать ему значения разных типов во время выполнения. any_cast используется для получения исходного значения правильного типа, который был сохранен в any объект. Например, ваш текущий класс позволяет вам сделать это

Properties p("int", 42);
std::cout << boost::any_cast<int>(p.value) << '\n';
p = Properties("string", std::string("hello"));
std::cout << boost::any_cast<std::string>(p.value) << '\n';

Вы не можете просто преобразовать класс выше в шаблон и получить идентичные функциональные возможности. Если вы сделаете это, вы сможете хранить только один тип значения. И вы должны изменить весь struct в шаблон, а не только конструктор.

template<typename T>
struct Properties {
public:
Properties() {}
Properties(std::string s, T p)
: name(std::move(s))   // should use initialization list instead
, value(std::move(p))  // of assignment within the body
{}

Properties(T n)
: value(std::move(n))
{}

std::string name;
T value;
};

Однако код, который я разместил выше, теперь является незаконным.

Properties<int> p("int", 42);
std::cout << p.value << '\n';
// p = Properties<std::string>("string", std::string("hello"));
// will not compile because Properties<int> and Properties<std::string> are
// distinct types

Если эти ограничения в порядке, то измененное определение должно работать для вас.

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector