A S
A S

Reputation: 85

Is it appropriate to have a template class with constructor overloading for each "type"

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

Answers (1)

Jarod42
Jarod42

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

Related Questions