Reputation: 85
I am new to using templates.
Is it appropriate to make a template class using constructor overloading for the various actual types?
For example:
template <typename T>
class A
{
A(..will receive paramaters for a specific type T);
A(..will receive DIFFERENT params for a different type T);
}
The code will compile because all functionality for each instantiation works, however logically (and practically) speaking, each constructor will be called depending on the type that I am actually using.
This suits my purpose well, but is this a correct "programming mindset"?
To be more specific - using SFML, here is what I am referring to, one will be a sprite and the other a shape, but with common functionality but exclusive too, such as the setColor or setTexture functions. What I mean is there will be no logical sense in calling the second constructor for T as a sprite:
template <typename T>
class GameObject {
public:
GameObject(sf::Texture& texture, sf::Vector2f pos)
{
m_drawable.setTexture(texture);
m_drawable.setOrigin(m_drawable.getGlobalBounds().width / 2, m_drawable.getGlobalBounds().height / 2);
m_drawable.setPosition(pos);
}
GameObject(sf::Color color, sf::Vector2f pos)
{
m_drawable.setColor(color);
m_drawable.setPosition(pos);
}
private:
T m_drawable;
};
Upvotes: 2
Views: 241
Reputation: 217810
As I understand, you would have only GameObject<Sprite>
and GameObject<Shape>
and use template to factorize some common code, but both classes have specific interface.
Then, IMO, it is bad to provide in interface methods to not use.
std::vector
provides some methods which has pre-requires on type T
(v.resize(count)
requires default insertable). But it is generic classes, combination would be huge, so acceptable IMO.
I think that non-common methods should be removed from GameObject<T>
In C++20, there is requires
which allow to "remove" methods conditionally:
template <typename T>
class GameObject {
public:
GameObject(sf::Texture&, sf::Vector2f pos) requires(std::is_same_v<Sprite, T>);
GameObject(sf::Color, sf::Vector2f pos) requires(std::is_same_v<Shape, T>);
// ...
};
SFINAE is an alternative for previous standard.
You might have 2 new classes GameSprite
/GameShape
which use/inherit a cleaned GameObject<T>
as implementation detail.
Alternatively, you might use (friend
) free function for the distinct behavior
template <typename T>
class GameObject {
GameObject(T&& t) : m_drawable(std::move(t)){}
public:
friend GameObject<Sprite> GameSprite(sf::Texture& texture, sf::Vector2f pos) {
Sprite sprite;
sprite.setTexture(texture);
sprite.setOrigin(sprite.getGlobalBounds().width / 2, sprite.getGlobalBounds().height / 2);
sprite.setPosition(pos);
return GameObject<Sprite>{std::move(sprite)};
}
friend GameObject<Shape> GameShape(sf::Color color, sf::Vector2f pos) { /*..*/}
// ...
};
Upvotes: 2