0

Here is a minimal simplification that reproduces the error I'm seeing in a larger codebase. In a nutshell, I want to model line segments using different numeric types (int, double, etc.)

template<typename T>
class Vector2
{
public:
  Vector2(T x, T y)
  : x(x), y(y)
  {}

  template<typename U>
  Vector2<U> cast() const { return Vector2<U>((U)x, (U)y); }

  T x;
  T y;
};

template<typename T>
class Line2
{
public:
  Line2(Vector2<T> a, Vector2<T> b)
  : a(a), b(b)
  {}

  double gradient() const
  {
    Vector2<double> ad(a.cast<double>()); // ERROR HERE
    Vector2<double> bd(b.cast<double>()); // ERROR HERE

    return (bd.y - ad.y) / (bd.x - ad.x);
  }

  Vector2<T> a;
  Vector2<T> b;
};

Some operations upon line segments require conversion of the coordinates to double, such as a gradient calculation. Hence the vector type supports casting.

The call to cast works fine when called like this:

Line2<int> i(Vector2<int>(0,0), Vector2<int>(1,3));
Line2<double> d(Vector2<double>(0,0), Vector2<double>(0.5,1.23));

The following code calls cast indirectly via the gradient member function:

Line2<int> i(Vector2<int>(0,0), Vector2<int>(1,3));
Line2<double> d(Vector2<double>(0,0), Vector2<double>(0.5,1.23));
std::cout << "Line2<int>.gradient = " << i.gradient() << std::endl;
std::cout << "Line2<double>.gradient = " << d.gradient() << std::endl;

This gives the following compilation error:

test.cpp: In member function ‘double Line2<T>::gradient() const’:
test.cpp:28:31: error: expected primary-expression before ‘double’
     Vector2<double> ad(a.cast<double>());
                               ^
test.cpp:28:31: error: expected ‘)’ before ‘double’
test.cpp:29:31: error: expected primary-expression before ‘double’
     Vector2<double> bd(b.cast<double>());
                               ^

Why does this error occur and how can I get around it?

I know that this could be worked-around by doing the case in the gradient arithmetic expression, but my actual code is more complex and uses the Eigen3 matrix classes. Mostly I just want to understand this error.

Full code and compilation error here: http://ideone.com/nwAdTN

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
  • I realize this isn’t code review, but please consider replacing the C-style casts like `(U)x` with `static_cast(x)`. Also, why don’t you provide a constructor `template explicit Vector2(Vector2 const &)` instead? – Christopher Creutzig Dec 27 '13 at 17:22
  • You really should consider using different names for your constructor formal arguments and your class data members... The compiler may be able to sort it with no issues, but it just looks confusing... – twalberg Dec 27 '13 at 17:29
  • Without even reading the question I knew it was a `template` problem. :) – David G Dec 27 '13 at 17:31
  • @twalberg, yes I never code like this. We use `d_` prefixes for all fields, and use functions for getters, keeping fields private. I just wanted the shortest code for the SO question. – Drew Noakes Dec 27 '13 at 17:32

1 Answers1

4

A dependent name is only considered to be a template if it is preceded by they keyword template. You need to call you function like this:

a.template cast<double>()

The basic idea is that the compiler should be able while parsing the template to decide what sort of entity it has encountered. Since the template parameters are unknown when reading the template definition it needs some help with knowing what it is seeing. It is similar to the needed typename when using nested names which are meant to be types.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • Thanks very much! I don't understand why the call works in one case, but not in the other. What is different about the two instances that means the compiler needs this tip? Is it something to do with nesting templates? – Drew Noakes Dec 27 '13 at 17:30
  • @DrewNoakes: the problem appear when you try to use a templated member function within a template using an object whose type depends on an outer template parameter. Since the object's type can be specialized, the compiler can't determine how the class looks like and determine that the accessed member happens to be a member function template. – Dietmar Kühl Dec 27 '13 at 17:37
  • Thanks again. While reading more about dependent names, I found this page which contains some nice motivating examples for the issue: http://en.cppreference.com/w/cpp/language/dependent_name – Drew Noakes Dec 27 '13 at 17:41
  • [This answer](http://stackoverflow.com/a/613132/24874) also provides some good reading on the topic. – Drew Noakes Dec 27 '13 at 17:50