I'm writing an Entity-Component-System framework for my game engine. Given that I intend for users to define their own structs and classes for components, I'm trying to make it as flexible as possible.
The problem is, I want to differentiate between objects that can be aggregate-initialized or initialized via their constructor. I know how to test if an object is constructible using the std::is_constructible
type trait. However, when I attempt to use it, it fails to compile. Below is a short snippet of the relevant code. Note that there are other procedures before this that handle error checking and array-pool management, but I think those are irrelevant.
template <typename ... Fields>
void add_component(Fields ... params) {
if(std::is_constructible<Component, Fields ...>::value) {
std::cout << "Yes!\n";
pool_[length_] = Component(params ...);
}
else {
std::cout << "No\n";
pool_[length_] = {params ...};
}
length_++;
}
I can clearly see that std::is_constructible
is correctly identifying objects that can be constructed, but it still attempts to call the constructor at compile-time. For example:
struct Vec2D {
float x, y;
};
If I attempt to add a Vec2D
component to my entity, it gives me the following error:
error: no matching function for call to ‘Dynamo::Vec2D::Vec2D(float&, float&)’
122 | pool_[length_] = Component(params ...);
| ^~~~~~~~~~~~~~~~~~~~~
In file included from src/main/../core/display.h:9,
from src/main/scene.h:9,
from src/main/engine.h:10,
from src/Dynamo.h:4,
from main.cpp:1:
src/main/../core/../util/vector.h:11:12: note: candidate: ‘Dynamo::Vec2D::Vec2D()’
11 | struct Vec2D {
| ^~~~~
src/main/../core/../util/vector.h:11:12: note: candidate expects 0 arguments, 2 provided
src/main/../core/../util/vector.h:11:12: note: candidate: ‘constexpr Dynamo::Vec2D::Vec2D(const Dynamo::Vec2D&)’
src/main/../core/../util/vector.h:11:12: note: candidate expects 1 argument, 2 provided
src/main/../core/../util/vector.h:11:12: note: candidate: ‘constexpr Dynamo::Vec2D::Vec2D(Dynamo::Vec2D&&)’
src/main/../core/../util/vector.h:11:12: note: candidate expects 1 argument, 2 provided
I expect the method to aggregate-initialize the component, but it still attempts to call the constructor. What is wrong here? Perhaps there is something wrong with how I used templates?
Edit: I'm aware of if constexpr()
, but I'm looking for a solution that could work with compiler versions before C++17. Is that still possible?