Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Cast Template

Tags:

c++

templates

I have this source code which allows me to cast a Point<float> to Point<double>:

template<class T> struct Point{
    template <typename NewType> Point<NewType> cast() const{
        return Point<NewType>();
    }       
};

int main(){
    Point<float> p1;
    Point<double> p2;
    p2 = p1.cast<double>();

    return 0;
}

This source code compiles well. Now, I add the following class and I have a compilation error at the line that does the cast:

template <class T> struct PointContainer{
    void test(){
        Point<T> p1;
        Point<double> p2;
        p2 = p1.cast<double>(); //compilation error
    }
};

Compilation error: error: expected primary-expression before ‘double’.

Why do I get this error and how can I solve it?

like image 852
Saelhenen Avatar asked Jun 23 '16 06:06

Saelhenen


3 Answers

Short answer: you need to add the keyword template right after the member access operator (the dot) in the line that is giving you the error.

Long answer: in PointContainer<T>, T is an unknown template variable. Since in C++ templates can have specializations that are allowed to be completely different from the base template, the compiler does not know if type Point<T> has a member cast that is a function template before substituting T for an actual type. That is why you can use the cast in main: Point<float> is a concrete type and the compiler knows that it does have that function template.

Since the compiler does not know the type of member that "cast" will be, it does not let you use operations that assume that it is a type, a template, or both. In order to do either you need to tell that to the compiler using the typename and template keywords. Imagine that in addition to your cast function template there is a typedef T value_type in Point<T>:

Point<float>::value_type f = 1.0f; // OK
Point<T>::value_type f = 1.0f; // Bad, compiler does not identify that as a type
typename Point<T>::value_type f = 1.0f; // OK

Point<float> pf;
Point<T> pT;
Point<double> pd1 = pf.cast<double>(); // OK
Point<double> pd2 = pT.cast<double>(); // Bad, compiler does not know cast is a template
Point<double> pd3 = pT.template cast<double>(); // OK
like image 175
Javier Martín Avatar answered Nov 13 '22 12:11

Javier Martín


Point<T> is a dependent-name (it depends on the template parameter T), so the compiler does not really know what Point<T>::cast is:

  • Point<T>::cast could be an attribute, then p1.cast < would be seen as a comparison with what's next.
  • Point<T>::cast could be a template (your case).

Since the compiler cannot know, it assumes the first one, hence your error (you cannot compare something with a type). To solve this, you need to explicitly tell the compiler that p1.cast is a templated method:

p2 = p1.template cast<double>();

For more information, see this question: Where and why do I have to put the "template" and "typename" keywords?

like image 29
Holt Avatar answered Nov 13 '22 12:11

Holt


    p2 = p1.cast<double>();

needs to be

    p2 = p1.template cast<double>(); 

The reason for that can be found at Where and why do I have to put the "template" and "typename" keywords?.

like image 35
R Sahu Avatar answered Nov 13 '22 11:11

R Sahu