Получение «ожидаемого первичного выражения» при вызове шаблонной функции из другой шаблонной функции

0

Вот минимальное упрощение, которое воспроизводит ошибку, которую я вижу в большей базе кода. В двух словах, я хочу моделировать сегменты линии, используя разные числовые типы (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

  • 0
    Я понимаю, что это не проверка кода, но, пожалуйста, рассмотрите возможность замены приведений в стиле C, таких как (U)x на static_cast<U>(x) . Кроме того, почему бы вам не предоставить вместо этого template <typename U> explicit Vector2(Vector2<U> const &) конструктора template <typename U> explicit Vector2(Vector2<U> const &) ?
  • 0
    @ChristopherCreutzig, спасибо за советы!
Показать ещё 3 комментария
Теги:
c++11
templates

1 ответ

4
Лучший ответ

Зависимое имя считается только шаблоном, если ему предшествует template ключевых слов. Вам нужно вызвать функцию:

a.template cast<double>()

Основная идея заключается в том, что компилятор должен иметь возможность анализировать шаблон, чтобы решить, какой тип сущности он встретил. Поскольку параметры шаблона неизвестны при чтении определения шаблона, ему нужна некоторая помощь, зная, что он видит. Он похож на нужное typename при использовании вложенных имен, предназначенных для типов.

  • 0
    Большое спасибо! Я не понимаю, почему вызов работает в одном случае, но не в другом. Чем отличаются эти два экземпляра, что означает, что компилятору нужен этот совет? Это как-то связано с вложенными шаблонами?
  • 0
    @DrewNoakes: проблема возникает, когда вы пытаетесь использовать шаблонную функцию-член в шаблоне, используя объект, тип которого зависит от внешнего параметра шаблона. Поскольку тип объекта может быть специализированным, компилятор не может определить, как выглядит класс, и определить, что доступный член является шаблоном функции-члена.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню