2014-01-17 4 views
1

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

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; 
}; 
+0

Программа использует переменную: std :: vector prop; и другой пример использования BOOST - boost :: any_cast (prop [i] -> value); – user3204803

ответ

5

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

////////////////////////////////////////// 
// 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"; 
} 

См выход Live On Coliru

+0

error: «virtual my_any :: storage_base :: ~ storage_base()» объявленный виртуальный не может быть установлен по умолчанию в классе класса. Также в строке: «Свойства (const std :: string & s = "", const my_any & p = {}) : name (s), value (p) {} "Я получаю ошибку: ожидаемое первичное выражение перед '{' токен – user3204803

+0

Ну ладно. Вы не назвали компилятор ...: | – sehe

+0

Итак, здесь: ** [MSVC12 ok] (http://rextester.com/CVHWF11127) **, [GCC 4.8 ok] (http://coliru.stacked-crooked.com/a/b3c84eac8fb77493), [Clang 3.5 ok] (http://coliru.stacked-crooked.com/a/69b25ed4f8b5a946). * AH *. Вы должны использовать [gcc 4.6] (http://coliru.stacked-crooked.com/a/a8ce7f08ccc0ff9b). Ну, исправление очевидно :) – sehe

1

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 

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

+0

Спасибо за ответ. Но ограничение не в порядке. Программа использует переменную: std :: vector prop; и другой пример использования BOOST - boost :: any_cast (prop [i] -> value); – user3204803

+2

@ user3204803, то, боюсь, вам придется придерживаться 'boost :: any' или сворачивать свои собственные. – Shoe

+0

@ user3204803 Боюсь, что Джефффри прав; в свою очередь, ваш собственный вариант - это единственный вариант. К счастью, 'boost :: any' относительно просто реализовать, [здесь] (http://www.boost.org/doc/libs/1_55_0/boost/any.hpp) исходный код (он получит много короче, если вы избавитесь от различных обходных путей компилятора и других опций) – Praetorian