传递std :: type_info来标识void *

时间:2018-06-28 18:36:19

标签: c++ c++11 templates template-meta-programming

我必须绕过void *以支持在编译时不知道的类型,但是我也不想完全发疯,把一切都留给自己,所以我认为对type_Checking使用type_info,但是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 :(得分:0)

您要执行的是实施任何一项,或使用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*,并以一种使滥用更加困难的方式键入信息。