Ошибка вывода аргумента шаблона при использовании списка инициализаторов в фигурных скобках
Я пытаюсь использовать вывод аргументов шаблона в функции 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 ответа
Проблема с {/*..*/}
в том, что он не имеет типа и может быть выведен только как 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]});
}
Один из вариантов - добавить перегрузку в perpendicular
который принимает два значения.
template <typename component>
offset<component> perpendicular(component v1, component v2) {
return {v2, -v1};
}
Это также можно сделать более универсальным с помощью пакетов параметров, возможно, в сочетании с std::common_type
.
Ответ 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.