Jump to content

  • Log In with Google      Sign In   
  • Create Account

Choosing implementation based on template arguments


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
9 replies to this topic

#1 TheComet   Members   -  Reputation: 1603

Like
0Likes
Like

Posted 15 November 2013 - 06:59 AM

In the following code:

template <class COORD>
class Foo
{
public:

    void setCoordinate( const COORD& coord ) { m_Coordinate = coord; }
    const COORD& getCoordinate() const { return m_Coordinate; }

    /* ... other methods ... */

private:

    COORD m_Coordinate;
    
    /* ... other data ... */
};

If I were to instantiate the class with the following code:

Foo<void> foo;

I would be forming a reference to "void", which would throw a compiler error.

 

Is there a way to completely omit the methods "setCoordinate" and "getCoordinate" as well as the data member "m_Coordinate" in the specific case where the template parameter COORD is void?

 

The class "Foo" still works without those methods in place, it's just more limited.


YOUR_OPINION >/dev/null


Sponsor:

#2 Icebone1000   Members   -  Reputation: 1086

Like
2Likes
Like

Posted 15 November 2013 - 07:11 AM

look for template specialization

template<>
class Foo<void>{
...implementation specific for foo<void>
};


#3 TheComet   Members   -  Reputation: 1603

Like
0Likes
Like

Posted 15 November 2013 - 07:25 AM

Oh you can specialize entire classes as well? Wow, how did I miss that...

 

So does this mean I'm forced to re-write the entire class specific to match a void template parameter? The class in question isn't exactly small, and the only thing that changes is omitting those two methods. That's a lot of redundant code.


YOUR_OPINION >/dev/null


#4 Brother Bob   Moderators   -  Reputation: 8196

Like
2Likes
Like

Posted 15 November 2013 - 07:28 AM

Then you can use a common base class that defines the common functions.

template<typename COORD> struct Foo_base
{
    /* common base members and methods */
};

template<typename COORD> struct Foo : Foo_base<COORD>
{
    void setCoordinate( const COORD& coord ) { m_Coordinate = coord; }
    const COORD& getCoordinate() const { return m_Coordinate; }

private:
    COORD m_Coordinate;
};

template<> struct Foo<void> : Foo_base<void>
{
};


#5 TheComet   Members   -  Reputation: 1603

Like
0Likes
Like

Posted 15 November 2013 - 07:33 AM

Thanks!


YOUR_OPINION >/dev/null


#6 TheComet   Members   -  Reputation: 1603

Like
0Likes
Like

Posted 15 November 2013 - 08:26 AM

Sorry, but another question arose. Say I wish to specialise single methods in the class for specific COORD arguments.

struct Vector2D
{
    Vector2D( int x, int y ) : x(x), y(y) {}
    int x;
    int y;
};

template <class COORD>
class Foo
{
public:
    void print( const COORD& coord );
};

template <class COORD>
void Foo<COORD>::print( const COORD& coord )
{
    std::cout << "Can't print - not specialised" << std::endl;
}

template <>
void Foo<Vector2D>::print( const Vector2D& coord )
{
    std::cout << "2D coordinates: " << coord.x << "," << coord.y << std::endl;
}

int main()
{
    Foo<int>().print(6);
    Foo<Vector2D>().print(Vector2D(3,5));
    return 0;
}

However, I'd like the user to have the ability to use their own Vector2D class - he could call it "Vec2" or something else. Obviously I can't see into the future, so I can't specialise a method beforehand.

 

With the assumption that every Vector2D class thrown at it should have public data members named "x" and "y", how can I solve this?


Edited by TheComet, 15 November 2013 - 08:27 AM.

YOUR_OPINION >/dev/null


#7 Brother Bob   Moderators   -  Reputation: 8196

Like
0Likes
Like

Posted 15 November 2013 - 08:38 AM

If you assume that any template parameter has an x and y member, then just access the x and y members.

template <class COORD>
void Foo<COORD>::print( const COORD& coord )
{
    std::cout << "2D coordinates: " << coord.x << "," << coord.y << std::endl;
}


#8 TheComet   Members   -  Reputation: 1603

Like
0Likes
Like

Posted 15 November 2013 - 09:11 AM

Ah, what I meant was that there could be completely other types as well which may or may not have "x" and "y", such as 1-dimensional types (which won't have "x" and "y"), or 3-dimensional types (which would have "x","y","z"), but would still count as coordinates, and require a specialised function to be dealt with.


Edited by TheComet, 15 November 2013 - 09:25 AM.

YOUR_OPINION >/dev/null


#9 Brother Bob   Moderators   -  Reputation: 8196

Like
1Likes
Like

Posted 15 November 2013 - 09:25 AM

The core of the problem is that your Foo class is responsible for printing the value of an arbitrary type. Delegate that work to the type itself, or at least the author of the type, instead. The Foo class then don't have to know how any arbitrary type wants to format itself, instead it lets the type print itself as it wants to.

 

And I am also going to assume that you want to print some member, for example m_Coordinate, and not just a parameter. Your example doesn't make sense as a member function since there's no need for it to access the object on which it is called.

namespace mynamespace
{
    struct myvector {};

    void format(myvector const &)
    {
        std::cout << "myvector" << std::endl;
    }
}

void format(int const &)
{
    std::cout << "int" << std::endl;
}
 
template<typename COORD> struct Foo : Foo_base<COORD>
{
    void print() {format(m_Coordinate);}

private:
    COORD m_Coordinate;
};

And while you're at it, pass the stream to the format function as well so you don't hard code it to cout. Now you add formatters for any type you need.



#10 King Mir   Members   -  Reputation: 2000

Like
0Likes
Like

Posted 15 November 2013 - 02:38 PM

Ah, what I meant was that there could be completely other types as well which may or may not have "x" and "y", such as 1-dimensional types (which won't have "x" and "y"), or 3-dimensional types (which would have "x","y","z"), but would still count as coordinates, and require a specialised function to be dealt with.

This kind of thing is possible with the use of enable_if or similar template meta-programming, especially if you make your member functions templates too, but as Brother Bob points out, you might want to reconsider the design.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS