使用花括号初始化器列表时模板参数推导失败
Template argument deduction fails when using braced initializer list
我正在尝试在 '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})
还是有办法给编译器一个提示?
{/*..*/}
的问题是它没有类型,并且大多只能推断为 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]});
}
给了你想要的语法,但我主观上认为它并不理想。本来想传一个偏移量,现在传一个数组,转成偏移量。这是一种奇怪的类型关系。
不用结构和单独的函数,只需将它们全部放入一个 Offset class。这实际上不是任何额外的工作,并且可以使 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)
作为您的 return 类型并放弃尾随的 return 类型语法,从 C++14 开始。
一个选项是向 perpendicular
添加一个重载,它采用两个值。
template <typename component>
offset<component> perpendicular(component v1, component v2) {
return {v2, -v1};
}
这也可以通过参数包变得更通用,可能与 std::common_type
结合使用。
我正在尝试在 '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})
还是有办法给编译器一个提示?
{/*..*/}
的问题是它没有类型,并且大多只能推断为 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]});
}
不用结构和单独的函数,只需将它们全部放入一个 Offset class。这实际上不是任何额外的工作,并且可以使 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)
作为您的 return 类型并放弃尾随的 return 类型语法,从 C++14 开始。
一个选项是向 perpendicular
添加一个重载,它采用两个值。
template <typename component>
offset<component> perpendicular(component v1, component v2) {
return {v2, -v1};
}
这也可以通过参数包变得更通用,可能与 std::common_type
结合使用。