#class using template<typename ...Args> must contain a method for each type in Args.

41 messages · Page 1 of 1 (latest)

severe reef
#

This is a lot of text, jump straight to QUESTION.

CONTEXT:
Well I've been struggling with the serializing architecture of my project. I am making a game engine and the custom content is very important so i have to template most of the things to support easy extension.
I've tried a lot of different approaches, but with the little experience i have with templates and metaprogramming they turned into dead ends. Now i finally think i have something.
So there is this class called SceneSerializer.

template<typename ...Components>
class SceneSerializer {
(...)
}

it must create a list of Actors that can then be serialized with a library.
An actor is just std::vector<std::variant<Components...>> a list of components

I use EnTT for the managing the scene. This library offers some support for serializing. I can give this library a Archive and it will call some operators for me that i can use to get the value of the components for all actors.

template<typename Component>
class SceneArchive : ArchiveBase {
public:
    void operator()(Actor actor0, Component component0) {
        // Here I have to notify Scene Serializer that a actor0 has component0
                // But SceneSerializer does not have any means of receiving it
    }

Note that SceneSerializer only uses the base class ArchiveBase. The problem is that SceneArchive is Components Specific and does not know the type of the variant that SceneSerializer needs. So SceneSerializer works with std::variant<A,B,C>. SceneArchive<A> has no means of knowing that it must provide a variant of <A,B,C>.

QUESTION:
Can templates be used so that a class like:

class SceneSerializer {
(...)
}```
can have a method set(Component component)  for each type in the packed parameter list 'Components' ? 

so SceneSerializer<A,B,C> must have 3 methods set(A a), set(B b), set(C c).
I think some metaprogramming and multiple inheritance could make it possible, but it way over my head.
azure joltBOT
#

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.

rich heath
#

like... a constraint? ```cpp
template<typename... Components>
requires((... && requires(Components foo, Components bar) {
foo.set(bar);
}))
class SceneSerializer {
// ...
};

severe reef
#

i am not sure that that is

rich heath
#

i must've misunderstood whoops

severe reef
#

the types used for Components are flat structures. they dont have any methods.

summer ivy
#

QUESTION:
Can templates be used so that a class like:
template<typename ...Components>
class SceneSerializer {
(...)
}

can have a method set(Component component) for each type in the packed parameter list 'Components' ?

so SceneSerializer<A,B,C> must have 3 methods set(A a), set(B b), set(C c).

In templates you usually have to assume something compiles, and then let the templates decide if it actually works

#

you can use constraints/requries to help with this

#

but its still not perfect

#

anyway

#

;compile -std=c++17

#include <iostream>

class A {};
class B {};
class C {};

class SceneSerializer {
public:
  void foo(A) const { std::cout << "A\n"; }
  void foo(B) const { std::cout << "B\n"; }
  void foo(C) const { std::cout << "C\n"; }
};

template<typename ... T>
void serialize(const SceneSerializer& ss, const T& ... ts) {
  (ss.foo(ts), ...);
}

int main() {
  SceneSerializer ss = {};

  serialize(ss, A{}, B{}, A{}, C{});
}
tender sunBOT
#
Program Output
A
B
A
C
summer ivy
#

(ss.foo(ts), ...); is a fold expression

#

pretty handy for variadic templates

rich heath
#

oh that's what they were asking

summer ivy
#

You can sort of do some inheritence things + other types to give SceneSerializer other methods but its usually more effort than just implementing them manually

#

I think thats what they want???

#

honestly didn't read the context only the final question

jaunty dew
#

Why not let the Component know how to serialize themselves?

summer ivy
#

can have a method set(Component component) for each type in the packed parameter list 'Components' ?
you don't want to use templates for this

#

you don't want these functions auto-generated

severe reef
#

i've been there. i though i had everything figured out, but my folding expression didnt complie and i changed the appoech to avoid that

summer ivy
#

As was suggested you likely don't want these as member functions on SceneSerializer
it makes extension harder

severe reef
#

I need to use template since i am making a game engine. the serializing process has to be transparent for the end user of the code that wants to create a new component

summer ivy
#

you probably want to use templates to call non-template functions in a specific way

jaunty dew
#

If the user can create a new Component you don't want the scene serializer to have a new function for each Component

summer ivy
#

I would prefer either member functions for serializing on the type, or template specializations

jaunty dew
#

I would suggest overload the << operator in each Component and using that to serialize

summer ivy
#

operator overloads aren't ideal here imo

#

overloading in general

#

let me illustrated the problem one sec

jaunty dew
#

In the end, some oneneeds to know how to serialize a Component, either the Scene Serializer, or the Component itself. And since the users can create new component, I think it's best if the Components know how to serialize themselves.

#

Or, you create some register macro

severe reef
#

well components do have some meta data used by the serializing library

#

but i think this is more about integrating the SceneArchive

#

the only way to sterialize the scene is via this SceneArchive.

#

i somehow need to transform the calls in the archive to operator()(Component component) to data in an centralized way. the calls to operator()(Component component) are somewhat chaotic. it is not until all the archives (Archive<A>, Archive<B>, Archive<C>) made thier calls that i can actually know what the scene really looks like

#

this is because EnTT uses the ECS design pattern and you never know what an actor looks like, the scene is a registry of components that relate in some way (are owned by the same actor). This is what makes serializeing challanging.

#

The only way i can think of right now is to make the Archive a template of template<typename MyComponent, typename ...AllComponents> class SceneArchive { std::varian<AllComponents> data; } this way i can query this field from the SceneSerializer.

#

this would only generate more code cuz for every SceneSerializer (SceneSerializer<A>, SceneSerializer<A,B>, SceneSerializer<A,B,C>) the SceneArchive will need to complie a diferent version. 1)SceneArchive<A,A> 2)SceneArchive<A,A,B>, SceneArchive<B,A,B> 3)SceneArchive<A,A,B,C>, SceneArchive<B,A,B,C>, SceneArchive<C,A,B,C>

severe reef
#

UPDATE: i went back to a previous attempt. i used a metafunction to turn the list of Componets (Components) into a tuple of archives of compoonets. ( A, B, C ---> tuple<Archive<A>, Archive<B>, Archive<C>> ) and then i used std::apply and a folding expression to make things work.