передача std :: type_info для идентификации void * - PullRequest
0 голосов
/ 28 июня 2018

Я должен обойти пустоту * для поддержки типов, которые не могут быть известны во время компиляции, но я также не хочу полностью сходить с ума и оставляю все на себе, поэтому я думаю использовать type_info для type_Checking, но так как type_info не поддерживает операцию копирования. Я получаю ошибки компилятора при их передаче

#include <bits/stdc++.h>

struct PropertyClassInterface {
    virtual const char * name() = 0;
    virtual void set(const char * property_name,std::pair<const void *,std::type_info> new_val) = 0;
    virtual std::pair<std::shared_ptr<void>,std::type_info> get(const char * property_name) = 0;
    template< typename Type>
    static std::pair<std::shared_ptr<void>,std::type_info> get_type_pair(const Type& Value) {
        std::shared_ptr<void> t = std::make_shared<Type>();
        *static_cast<Type *>(t.get()) = Value;
        *return std::make_pair(t,typeid(Type));* // error
    }
};

struct PropertyManager {
    using base_pointer = std::shared_ptr<PropertyClassInterface>;
    void add_object(base_pointer new_member) {
        objects.push_back(new_member);
    }
    template<typename Type>
    void set(const char * object_name,const char * property_name,const Type& new_val) {
        find_object_orThrow(object_name)->set(property_name,std::make_pair(static_cast<const void *>(&new_val),typeid(new_val)));
    }
    template<typename Type>
    Type get(const char * object_name, const char * property_name) {
        auto a = find_object_orThrow(object_name)->get(property_name);
        if (typeid(Type).hash_code() != a.second.hash_code())
            throw std::runtime_error{"get(): mismatched type"};
        return a.first;
    }
public:
    std::vector<base_pointer> objects;
    base_pointer find_object_orThrow(const char * obj_name){
        for(auto& o : objects) {
            if (!strcmpi(o->name(),obj_name)) {
                return o;
            }
        }
        throw std::runtime_error{std::string("no object named \"") + obj_name + "\" found"};
    }
};

struct testClass : PropertyClassInterface {
    void set(const char * property_name,std::pair<const void *,std::type_info> new_val) {
        auto checkTypeInfo = [&new_val](const std::type_info& expected) {
            if (new_val.second.hash_code() != expected.hash_code())
                throw std::runtime_error{"set(): wrong type"};
        };
        if (!strcmpi(property_name,"my_number")) {
            checkTypeInfo(typeid(decltype(my_number)));
            my_number = *static_cast<const decltype(my_number) *>(new_val.first);
        }
    };
    std::pair<std::shared_ptr<void>,std::type_info> get(const char * property_name) {
        if (!strcmpi(property_name,"my_number")) {
            PropertyClassInterface::get_type_pair(my_number);
        }
    }
private:
    int my_number;
};

int main() {
};

поэтому я должен использовать динамическую память для хранения type_info
Я ограничен C ++ 11, и я знаю о том, что я не использую битовые заголовки, и я использую только для тестирования

1 Ответ

0 голосов
/ 29 июня 2018

То, что вы хотите сделать, это реализовать any или использовать boost any.

Любой не сложно написать.

namespace details {
  struct any_concept;
  using pimpl=std::unique_ptr<any_concept>;
  struct any_concept {
    virtual ~any_concept() {}
    virtua pimpl clone() const = 0;
    virtual std::type_info const& type() const = 0;
  private:
    virtual void* unsafe_get() = 0;
    virtual void const* unsafe_get() const = 0;
  public:
    template<class T>
    T* get() {
      if (typeid(T) != type()) return nullptr;
      return static_cast<T*>(unsafe_get());
    }
    template<class T>
    T const* get() const {
      if (typeid(T) != type()) return nullptr;
      return static_cast<T const*>(unsafe_get());
    }
  };

  template<class T>
  struct any_model:any_concept {
    T t;
    virtual ~any_model() = default;
    virtual pimpl clone() const final override {
      return pimpl( new any_model(t) );
    }
    virtual std::type_info const& type() const final override {
      return typeid(T);
    }
    template<class U>
    any_model(U&& u):t(std::forward<U>(u)){}
  private:
    virtual void* unsafe_get() final override { return std::addressof(t); }
    virtual void const* unsafe_get() const final override { return std::addressof(t); }
  };
}    
struct any {
  template<class T, typename std::enable_if<!std::is_same<any, typename std::decay<T>::type>::value, bool> =true>
  any( T&& t ):
    pImpl( new details::any_model<typename std::decay<T>::type>( std::forward<T>(t) ) )
  {}
  template<class T>
  T* get() {
    if (!pImpl) return nullptr;
    return pImpl->get<T>();
  }
  template<class T>
  T const* get() const {
    if (!pImpl) return nullptr;
    return const_cast<details::any_concept const&>(*pImpl).get<T>();
  }
  template<class T>
  bool contains()const { return get<T>(); }
  explicit operator bool() const {
    return (bool)pImpl;
  }
  any()=default;
  any(any&&)=default;
  any& operator=(any&&)=default;
  ~any()=default;

  any(any const& o):
    pImpl( o.pImpl?o.pImpl->clone():pimpl{} )
  {}
  any& operator=(any const& o) {
    any tmp(o);
    std::swap(*this, tmp);
    return *this;
  }
private:
  details::pimpl pImpl;
};

есть; действительно простая any реализация. Написано на телефоне, поэтому, вероятно, содержит опечатки.

Он поддерживает семантику значений, но сохраняет все (что может быть скопировано и уничтожено). Если вы знаете, что он хранит, вы можете .get<T>() это. Вы также можете спросить, если это contains<T>().

Это известно как словарный тип. Это в основном ваш void* и информация о типе, объединенная таким образом, что делает злоупотребление более трудным.

...