简体   繁体   中英

passing std::type_info for identifying void *

I have to pass around the void * for supporting types that can't be known at compile time, but I also don't want to go totally insane and left everything on myself so I think to use type_info for type_Checking but since type_info doesn't support copy operation I am getting compiler errors when passing them around

#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() {
};

so do I have to use dynamic memory for storing type_info as well
I am limited to c++11 and I know about not using bits headers and am only using for testing

What you want to do is implement an any, or use boost any.

An any isn't hard to write.

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

there; a really simple any implementation. Written on a phone, so probably contains typos.

It supports value semantics, but store anything (that can be copied and destroyed). If you know what it stores, you can .get<T>() it. You can ask it if it contains<T>() as well.

This is known as a vocabulary type. It is basically your void* and type info bundled in a way that makes misuse more difficult.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM