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\$

closed as off-topic by 200_success, Toby Speight, Vogel612 Sep 26 at 9:46

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Code not implemented or not working as intended: Code Review is a community where programmers peer-review your working code to address issues such as security, maintainability, performance, and scalability. We require that the code be working correctly, to the best of the author's knowledge, before proceeding with a review." – 200_success, Toby Speight, Vogel612
If this question can be reworded to fit the rules in the help center, please edit the question.

  • \$\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 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 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.