Сбой вывода аргументов шаблона при использовании списка инициализированных фигурных скобок - PullRequest
2 голосов
/ 26 сентября 2019

Я пытаюсь использовать вывод аргумента шаблона в функции 'perpendicular ()':

#include <iostream>

template <typename component = double>
struct offset {
  component x;
  component y;
};

template <typename component>
offset(component x, component y) -> offset<component>;

template <typename component>
offset<component> perpendicular(offset<component> const &o) {
  return offset{o.y, -o.x};
}

template <typename component>
std::ostream &operator<<(std::ostream &s, offset<component> const &o) {
  return s << '(' << o.x << ", " << o.y << ')';
}

int main() {
  std::cout << perpendicular({3.1, 1.2}) << '\n';
  return 0;
}

Это, однако, не компилируется;Clang (с -std='c++17') говорит: candidate template ignored: couldn't infer template argument 'component' offset<component> perpendicular(offset<component> const &o) {.

Должен ли я отказаться от написания perpendicular(offset{1.0, 2.0}) или есть способ дать подсказку компилятору?

Ответы [ 3 ]

3 голосов
/ 26 сентября 2019

Проблема с {/*..*/} заключается в том, что он не имеет типа и в большинстве случаев может быть выведен только как std::initializer_list<T> или T[N].

. Таким образом, следующий код разрешит желаемый синтаксис:

template <typename component>
offset<component> perpendicular(component const (&o)[2]) {
    return offset{o[1], -o[0]};
    // return perpendicular(offset{o[0], o[1]});
}

Демо

0 голосов
/ 26 сентября 2019

Один из вариантов - добавить перегрузку к perpendicular, которая принимает два значения.

template <typename component>
offset<component> perpendicular(component v1, component v2) {
    return {v2, -v1};
}

Это также можно сделать более общим для пакетов параметров, возможно, в сочетании с std::common_type.

0 голосов
/ 26 сентября 2019

Ответ Jarod42 дает вам синтаксис, который вы хотите, но я субъективно думаю, что он не идеален.Изначально вы хотели передать смещение, но теперь вы передаете массив и превращаете его в смещение.Это странное отношение типов.

Вместо структуры и отдельных функций просто поместите все это в класс Offset.На самом деле это не какая-то дополнительная работа, и она делает C ++ лучше.То, что у вас есть, больше похоже на объектно-ориентированный C.

#include <iostream>

// Create a self-contained class
template <typename Component = double>
class Offset {
 public:
  Offset(Component x, Component y) : x(x), y(y) {}

  // No longer requires function parameters
  Offset const perpendicular() const { return Offset(y, -x); }

  // I appreciate your use of east const
  friend std::ostream& operator<<(std::ostream& sout,
                                  Offset<Component> const& o) {
    return sout << '(' << o.x << ", " << o.y << ')';
  }

 private:
  Component x;
  Component y;
};

int main() {
  // Subjectively much cleaner to read and understand
  std::cout << Offset{3.1, 1.2}.perpendicular() << '\n';
  return 0;
}

Для дальнейшего использования можно использовать decltype(auto) в качестве возвращаемого типа и полностью отказаться от синтаксиса завершающего возвращаемого типа начиная с C ++ 14.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...