0
votes

I want to make a event class having a member of any types of data, and make it a non-template class. but it can set content giving a template type of content. I have handler functions which are using content of event class.

NewEvent.h file

class NewEvent {
public:
  NewEvent(const int64_t& value = 0) : value_(value) {}

  int64_t value() const { return value_; }
  void set_value(const int64_t& value) { value_ = value; }

  class ElementBase {
  public:
    virtual ~ElementBase() {}
    template <typename ContentT> ContentT& content() const;
    template <typename ContentT> void set_content(const ContentT&);
  };

  template <typename ContentT, typename Allocator = std::allocator<ContentT>>
  class Element : public ElementBase {
  public:
    Element(const Allocator& alloc = Allocator()) : alloc_(alloc) {}

    typedef std::allocator_traits<Allocator> AllocatorTraits;

    ContentT& content() const {
      return content_;
    }
    void set_content(const ContentT& content) {
      AllocatorTraits::construct(alloc_, &content_, content);
    }

  protected:
    ContentT content_;
    Allocator alloc_;
  };

  template <typename ContentT>
  void set_content(ContentT& content) {
    ElementBase* element = new Element<ContentT>();
    element->set_content(content);
    content_.reset(element);
  }

  template <typename ContentT>
  ContentT& content() const {
    return content_->content<ContentT>();
  }

private:
  int64_t value_;

  std::unique_ptr<ElementBase> content_;
};

template <typename ContentT>
ContentT& NewEvent::ElementBase::content() const {
  return dynamic_cast<NewEvent::Element<ContentT>&>(*this).content();
}

template <typename ContentT>
void NewEvent::ElementBase::set_content(const ContentT& content) {
  dynamic_cast<NewEvent::Element<ContentT>&>(*this).set_content(content);
}

Main.cpp

struct Data {
    int returns;
};
void print(Data data) {
}
int main() {
    struct Data data;
    // ...
    NewEvent new_event;
    new_event.set_content<Data>(data);

    print(new_event.content());
    return 0;
}

in my code, set_content function works well. but I don't know how to receive content() and call according to type of content. content() function in NewEvent class has a compile error.

error C2783: 'ContentT &NewEvent::ElementBase::content(void) const' : could not deduce template argument for 'ContentT'

How to solve this deducing type problem, or is there other methods to implement like this?

1

1 Answers

0
votes

In your function:

template <typename ContentT>
ContentT& content() const { .. }

ContentT here cannot be deduced - you're not providing anything when you call it that the compiler can use to determine which version of content() to call (hence the error). How can it know whether you want content<Date>() or content<int>() or ...? You have to explicitly provide the type at the call site in the same way you did when you called set_content():

print(new_event.content<Date>()); // now compiler knows which content() to call.

(Note that what you're implementing is effectively the same as boost::any, in case you want to use that type instead.)