#Iterate over tuple and call template function on each element

107 messages · Page 1 of 1 (latest)

harsh widget
#

I have something like this:

template<typename PrimitiveType>
struct PackedVector
{
    std::unordered_map<uint32_t, uint32_t> m_ID_to_Index;
    std::unordered_map<uint32_t, uint32_t> m_Index_to_ID;
    std::vector<PrimitiveType> m_Data;

    void Add(uint32_t ID, PrimitiveType Type)
    {
        // Do stuff
    }

    void Remove(uint32_t ID)
    {
        // Do stuff
        printf("Remove\n");
    }
};

template<typename ...Args>
class RenderProxyClass
{
private:
    std::tuple<PackedVector<Args>...> m_PrimitiveTuple;

public:
    RenderProxyClass() = default;

    void Remove(uint32_t ID)
    {
        std::get<PackedVector<int>>(m_PrimitiveTuple).Remove(ID);
        std::get<PackedVector<double>>(m_PrimitiveTuple).Remove(ID);
        std::get<PackedVector<std::string>>(m_PrimitiveTuple).Remove(ID);
    }

};

using RenderProxy = RenderProxyClass<int, double, std::string>;

// Main
int main()
{
    RenderProxy Proxy;
    Proxy.Remove(0);
    return 0;
}

This works, but I want to iterate over the tuple and call the remove function with each "arg" parameter type, instead of having to manually call ::Remove for each type.

I did something like this using folding expressions:

// Inside the PackedVector class
using Type = PrimitiveType;

// Inside the proxy class
void Remove(uint32_t ID)
{
    std::apply([this, ID](auto&&...args)
        { ((this->Remove<typename auto::Type>(ID)), ...); } , m_PrimitiveTuple
    );
}

But this doesnt compile and complains with:

'auto' was unexpected here; expected 'id-expression'

So what should I do to get the ::Type type?

Thank you

candid egretBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

simple aurora
harsh widget
#

maybe im missunderstanding the fold expression

simple aurora
#

can you show more of the error please

#

ohh

inner iron
#

Just gonna mention you can fold over comma operator

simple aurora
#

should that be something like this->template Remove<typename decltype(args)::Type>(ID)?

harsh widget
#

im still new to fold expressions

simple aurora
#

idk

inner iron
#

The pack of the class template is accessible in the member function

harsh widget
inner iron
#

I'm not on desktop right now

harsh widget
#

similar error

inner iron
#

Cause of the universal reference

simple aurora
#

i think he means you still have access to Args... within the Remove function

inner iron
harsh widget
harsh widget
#

i need one per fold

inner iron
simple aurora
#

not sure

inner iron
#

Well I guess you'll have to wait for someone else, of for me to get back, or for ez to get to the bottom of the other thing

#

Well I wouldn't have relied on the unknown template remove but I guess

harsh widget
#

just to clarify, i need the template instantiation of the remove function to be the same arguments as when i alias the RenderProxy class

simple aurora
#

i think a prior error was related to this

inner iron
#

Did he ever share the template remove

simple aurora
#

what is a template remove

inner iron
#

The template non-static member function Remove

harsh widget
#

ffs

#

im sorry lol

simple aurora
#

ohhh

inner iron
#

Or whatever Remove is

harsh widget
#

1sec

inner iron
#

That you've written in your example

harsh widget
#

i wrote wrong in my example. i ported it and made it smaller for u

#

1sec

simple aurora
#

i thought 'template remove' was some fancy name for something to do with the template keyword

inner iron
#

Enough was shared about other things to write a version that didn't rely on an unknown function

simple aurora
#

a

harsh widget
#

1sec gonna try some stuff

#

basically, what i want, is that the PackedVector::Remove is called for each instantiation in the tuple, if that makes sense

#
std::apply([this, ID](auto&&...args)
    { ((this->Remove(ID)), ...); }, m_PrimitiveTuple
);
#

kinda like this

#

but instead of this->Remove() i want to call for the PackedVector

inner iron
#

;compile

#include <iostream>
#include <tuple>
#include <stdint.h>

template<typename PrimitiveType>
struct PackedVector
{
    void Remove(uint32_t ID)
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

template<typename ...Args>
class RenderProxyClass
{
private:
    std::tuple<PackedVector<Args>...> m_PrimitiveTuple;

public:
    RenderProxyClass() = default;

    void Remove(uint32_t ID)
    {
        (..., std::get<PackedVector<Args>>(m_PrimitiveTuple).Remove(ID));
    }

};

using RenderProxy = RenderProxyClass<int, double, std::string>;

// Main
int main()
{
    RenderProxy Proxy;
    Proxy.Remove(0);
    return 0;
}
ancient steepleBOT
#
Program Output
void PackedVector<PrimitiveType>::Remove(uint32_t) [with PrimitiveType = int; uint32_t = unsigned int]
void PackedVector<PrimitiveType>::Remove(uint32_t) [with PrimitiveType = double; uint32_t = unsigned int]
void PackedVector<PrimitiveType>::Remove(
inner iron
#

well with the output limitation that doesn't look "great" but whatever

#

point being that if all the types in your pack Args are unique, this is fairly easy to do through fold expressions

#

if your types aren't actually unique, you'd have to go through indices

#

or I guess you could use apply but I don't like that

harsh widget
#

but my PackedVector doesnt have the instantiation of all the Args, right? it only has of one of the types given to the variadic class, right?

#

so why can i do PackedVector<Args>?

inner iron
inner iron
#

PackedVector takes one type argument

#

PackedVector<Args> does not mean you pass all the element in the pack into one template

harsh widget
#

ah right. its the ... that repeats per pack element, right?

#

then it makes sense

inner iron
#

when you expand a pack or use a fold, the name of the pack acts as a placeholder for one element in the pack

harsh widget
#

right, i mixed it up, thanks!

#

then it makes sense

#

i thougth the "args" in the std::apply part was the non-expanded ones, but the ... in the lambda argument list expands the pack, right?

candid egretBOT
#

@harsh widget Has your question been resolved? If so, type !solved :)

simple aurora
#

oh wow i open this just as you start typing

harsh widget
#
void RemoveEntity(const std::string& Name)
{
    if (auto Entity = m_Entities.find(Name); Entity != m_Entities.end())
    {
        ECS::EntityID ID = Entity->second.GetEntityID();
        std::apply(
            [this, ID](auto&& ... args)
            { (args.Remove(ID), ...); }, 
            m_RenderProxy.GetPrimitiveTuple()
        );
        m_Entities.erase(Name);
    }
}
```Beautiful
#

thanks guys

simple aurora
#

that looks neat

harsh widget
#

i both have a better idea of fold expr and param packs now. atleast i learned something!

harsh widget
#

im working on my scene class in my engine

simple aurora
#

wait how does ; , work there

harsh widget
#

and im tired of needing to add new code for every primitive

harsh widget
simple aurora
simple aurora
#

i don't see a closing }

#

oh well

harsh widget
#

oh, sorry, i fked up copy paste

simple aurora
#

looks excellent

harsh widget
#

!solved

candid egretBOT
#

Thank you and let us know if you have any more questions!

This thread is now set to auto-hide after an hour of inactivity

simple aurora
harsh widget
#

m_RenderProxy is a member variable of the calling class

inner iron
#

it's not used in the lambda

simple aurora
#

^

harsh widget
#

ah fml yeah ofc

#

as i said

#

its an argument

#

lmao

simple aurora
#

what

#

ok

#

your code looks good

harsh widget
#

what being up to 6am at new years does to a dude

simple aurora
#

haha

#

happy new year

harsh widget
#

haha u2

#

still hangover after like 16 hours