0
\$\begingroup\$

I was able to get some very helpful code to get tuple values on a previous question. I was able to reduce my duplication a lot. But I'm having trouble wrapping this code in its own helper class so it can be reused in other classes. How can I improve this code to allow this?

This is the tuple code:

// Inserted invoke to use `void` as filling for holes
template<class T, class F>
constexpr auto invoke(F &&f, std::size_t I) -> std::enable_if_t<!std::is_same<T, void>::value> {
    f((T *) 0, I);
}

template<class T, class F>
constexpr auto invoke(F &&, std::size_t) -> std::enable_if_t<std::is_same<T, void>::value> {
}

template<class tuple, class F, std::size_t... I>
constexpr void forAllTypesImpl(F &&f, std::index_sequence<I...>) {
    int x[] = {0, (invoke<std::tuple_element_t<I, tuple>>(f, I), 0)...};
    static_cast<void>(x);
}

template<class tuple, class F>
void forAllTypes(F &&f) {
    forAllTypesImpl<tuple>(f, std::make_index_sequence<std::tuple_size<tuple>::value>());
}

template<class R, class tuple, class F>
R getOne(F &&f, std::size_t i) {
    R r;
    forAllTypes<tuple>([&](auto p, std::size_t j) {
        if (i == j) {
            r = f(p);
        }
    });
    return r;
}

I have a method that uses this code to create an event class instance by passing an event type enum:

using eventClasses = std::tuple<Event::SetMatchType, Event::SetTeam, Event::SetPlayer, Event::StartMatch, void, void, Event::StartInnings, Event::StartOver, Event::Ball, Event::ExtraBall, Event::Wicket, Event::Penalty, Event::Retire, Event::EndOver, Event::EndInnings, void, Event::EndMatch, Event::SwapBatsman, void, Event::NewBatsman, Event::NewBowler, Event::NewWicketKeeper, Event::SetCaptain, void, void, Event::Undo>;

template<class... X, class ET>
std::shared_ptr<Event> Event::createInstance(const ET eventType, X&&... x) {
    return getOne<std::shared_ptr<Event>, eventClasses>([&](auto p) {
        return std::make_shared<std::decay_t<decltype(*p)>>(std::forward<X>(x)...);
    }, static_cast<std::size_t>(eventType));
}

To create an event class, I give it an enum and the parameters it needs for the constructor (in this case json):

auto event = createInstance(eventType, serializedJson);

The code above works just fine on it's own. I try to improve the code myself and move it into its own helper class and then I get this error (hopefully helpfuly information, otherwise ignore it):

Error: Undefined symbol 'rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const& TupleHelper::getOne<std::__1::shared_ptr<Event>, std::__1::tuple<Event::SetMatchType, Event::SetTeam, Event::SetPlayer, Event::StartMatch, void, void, Event::StartInnings, Event::StartOver, Event::Ball, Event::ExtraBall, Event::Wicket, Event::Penalty, Event::Retire, Event::EndOver, Event::EndInnings, void, Event::EndMatch, Event::SwapBatsman, void, Event::NewBatsman, Event::NewBowler, Event::NewWicketKeeper, Event::SetCaptain, void, void, Event::Undo, Event::AuditRemove, void, Event::AuditAddBall, Event::AuditModify, Event::AddNote, Event::RemoveNote, Event::AddPauseNote, Event::AddPowerPlay, Event::RemovePowerPlay, Event::ReplacePlayer, void, void, void, void, Event::ResumeMatch, Event::AuditModifyRetirement, Event::OutfieldSpeed, Event::BounceLevel, Event::TurnLevel, Event::UpdatePlayer, Event::FieldAggression, Event::BoundaryRopeRegression, Event::Weather, Event::PlayerOfTheMatch, Event::SetToss, void, Event::SetRunIn, Event::SetDanger, Event::SetBattingOrder, Event::UmpireReview, Event::TeamReview, Event::SetInjuredPlayer, Event::UninjuredPlayer, Event::ReviewOutcome, Event::DeviceInformation, Event::EditModifyAction, Event::EditInsertAction, Event::EditRemoveAction>, std::__1::shared_ptr<Event> Event::createInstance<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&, EventType>(EventType, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&&&)::'lambda'(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&)>(std::__1::shared_ptr<Event> Event::createInstance<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&, EventType>(EventType, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&&&)::'lambda'(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&)&&, unsigned long)' referenced from:

Error: std::__1::shared_ptr<Event> Event::createInstance<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&, EventType>(EventType, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&&&) in Event.o

Can someone work out how to improve the code and move it into its own class?

\$\endgroup\$
5
  • \$\begingroup\$ @Jamal, the code that is posted here is working. \$\endgroup\$ – Daniel Ryan Jul 3 '17 at 3:31
  • \$\begingroup\$ What about the error? \$\endgroup\$ – Jamal Jul 3 '17 at 3:51
  • \$\begingroup\$ I've asked for code improvements so this can be used in its own class (it works just fine otherwise). The error is to explain what happens when I try to do this. I've edited the above to make this clearer. \$\endgroup\$ – Daniel Ryan Jul 3 '17 at 4:02
  • \$\begingroup\$ I'm afraid this question does not match what this site is about. Code Review is about improving existing, working code. Code Review is not the site to ask for help in fixing or changing what your code does. Once the code does what you want, we would love to help you do the same thing in a cleaner way! Please see our help center for more information. \$\endgroup\$ – Vogel612 Sep 26 '19 at 9:47
  • \$\begingroup\$ @Vogel612 My post clearly explains that this code works. It was about improving it to be moved into its own class and make it reusable. The error was extra helpful information. I already solved my issue in 2017, so why are you putting this on hold now? \$\endgroup\$ – Daniel Ryan Sep 26 '19 at 20:53
0
\$\begingroup\$

Looks like if I have all the code in its own header file (no class file) it works just fine. Not ideal, but will do until someone can figure a better solution.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.