Вот минимальное упрощение, которое воспроизводит ошибку, которую я вижу в большей базе кода. В двух словах, я хочу моделировать сегменты линии, используя разные числовые типы (int
, double
и т.д.),
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;
};
Некоторые операции по сегментам линии требуют преобразования координат в double
, например вычисления градиента. Следовательно, векторный тип поддерживает литье.
Призыв к cast
отлично работает при вызове так:
Line2<int> i(Vector2<int>(0,0), Vector2<int>(1,3));
Line2<double> d(Vector2<double>(0,0), Vector2<double>(0.5,1.23));
Следующие вызовы кода cast
косвенно через gradient
функции члена:
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;
Это дает следующую ошибку компиляции:
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>());
^
Почему эта ошибка возникает и как я могу обойти ее?
Я знаю, что это можно было бы обойти, выполнив этот случай в градиентном арифметическом выражении, но мой фактический код более сложный и использует матричные классы Eigen3. В основном я просто хочу понять эту ошибку.
Полный код и ошибка компиляции здесь: http://ideone.com/nwAdTN
Зависимое имя считается только шаблоном, если ему предшествует template
ключевых слов. Вам нужно вызвать функцию:
a.template cast<double>()
Основная идея заключается в том, что компилятор должен иметь возможность анализировать шаблон, чтобы решить, какой тип сущности он встретил. Поскольку параметры шаблона неизвестны при чтении определения шаблона, ему нужна некоторая помощь, зная, что он видит. Он похож на нужное typename
при использовании вложенных имен, предназначенных для типов.
(U)x
наstatic_cast<U>(x)
. Кроме того, почему бы вам не предоставить вместо этогоtemplate <typename U> explicit Vector2(Vector2<U> const &)
конструктораtemplate <typename U> explicit Vector2(Vector2<U> const &)
?