调用一个特别没有模板化的函数
Call a function that is specifically not templated
我有一堆函数可以检查各种形状之间的碰撞。
bool Collides(Rect r, Circle c);
bool Collides(Rect r, Line l);
bool Collides(Line l, Circle c);
我希望我可以实现一个模板化函数,通过允许它交换输入参数来将我的实现数量减半。这样就不必实施:
// The same as before but the input parameters swapped
bool Collides(Circle c, Rect r) { return Collides(r, c); }
bool Collides(Line l, Rect r) { return Collides(r, l); }
bool Collides(Circle c, Line l) { return Collides(l, c); }
我可以改写一次:
template <typename Shape1, typename Shape2>
bool Collides(Shape1 a, Shape2 b)
{
return Collides(b, a);
}
不幸的是,当 Collides(a, b)
和 Collides(b, a)
都未实现时,它会在运行时递归调用模板函数,这显然是意外行为。
是否有某些 C++ 标记或功能允许您关闭或禁止指定行或块的参数类型推导?目的是强制编译器寻找非模板化实现,如果不存在则编译失败。
无法从重载集中删除函数模板。在您的特定情况下,有一些解决方法,例如:
struct CollidesImpl {
bool operator()(Rect r, Circle c);
bool operator()(Rect r, Line l);
bool operator()(Line l, Circle c);
};
template <typename Shape1, typename Shape2>
bool Collides(Shape1 a, Shape2 b)
{
static_assert(std::is_invocable_v<CollidesImpl, Shape1, Shape2> ||
std::is_invocable_v<CollidesImpl, Shape2, Shape1>,
"No implementation exists for these argument types");
if constexpr(std::is_invocable_v<CollidesImpl, Shape1, Shape2>) {
return CollidesImpl{}(a, b);
} else {
return CollidesImpl{}(b, a);
}
}
有一次不查找函数模板是在函数声明期间(在开始之前{
)。利用这一点,我们可以得出 SFINAE 未实现的参数:
template<typename Shape1, typename Shape2>
auto Collides(Shape1 a, Shape2 b) -> decltype(::Collides(b, a)) {
return Collides(b, a);
}
但请注意,这必须写在 Collides
的所有其他声明之后。
您也可以只调用委托的不同函数:
template<typename Shape1, typename Shape2>
auto ActualCollides(Shape1 a, Shape2 b) -> decltype(Collides(a, b)) {
return Collides(a, b);
}
template<typename Shape1, typename Shape2>
auto ActualCollides(Shape1 a, Shape2 b) -> decltype(Collides(b, a)) {
return Collides(b, a);
}
// Or rename `Collides` into `CollidesImpl` and you can call this `Collides` instead
由于 ADL,这将考虑到未来的 Collides
功能。
我有一堆函数可以检查各种形状之间的碰撞。
bool Collides(Rect r, Circle c);
bool Collides(Rect r, Line l);
bool Collides(Line l, Circle c);
我希望我可以实现一个模板化函数,通过允许它交换输入参数来将我的实现数量减半。这样就不必实施:
// The same as before but the input parameters swapped
bool Collides(Circle c, Rect r) { return Collides(r, c); }
bool Collides(Line l, Rect r) { return Collides(r, l); }
bool Collides(Circle c, Line l) { return Collides(l, c); }
我可以改写一次:
template <typename Shape1, typename Shape2>
bool Collides(Shape1 a, Shape2 b)
{
return Collides(b, a);
}
不幸的是,当 Collides(a, b)
和 Collides(b, a)
都未实现时,它会在运行时递归调用模板函数,这显然是意外行为。
是否有某些 C++ 标记或功能允许您关闭或禁止指定行或块的参数类型推导?目的是强制编译器寻找非模板化实现,如果不存在则编译失败。
无法从重载集中删除函数模板。在您的特定情况下,有一些解决方法,例如:
struct CollidesImpl {
bool operator()(Rect r, Circle c);
bool operator()(Rect r, Line l);
bool operator()(Line l, Circle c);
};
template <typename Shape1, typename Shape2>
bool Collides(Shape1 a, Shape2 b)
{
static_assert(std::is_invocable_v<CollidesImpl, Shape1, Shape2> ||
std::is_invocable_v<CollidesImpl, Shape2, Shape1>,
"No implementation exists for these argument types");
if constexpr(std::is_invocable_v<CollidesImpl, Shape1, Shape2>) {
return CollidesImpl{}(a, b);
} else {
return CollidesImpl{}(b, a);
}
}
有一次不查找函数模板是在函数声明期间(在开始之前{
)。利用这一点,我们可以得出 SFINAE 未实现的参数:
template<typename Shape1, typename Shape2>
auto Collides(Shape1 a, Shape2 b) -> decltype(::Collides(b, a)) {
return Collides(b, a);
}
但请注意,这必须写在 Collides
的所有其他声明之后。
您也可以只调用委托的不同函数:
template<typename Shape1, typename Shape2>
auto ActualCollides(Shape1 a, Shape2 b) -> decltype(Collides(a, b)) {
return Collides(a, b);
}
template<typename Shape1, typename Shape2>
auto ActualCollides(Shape1 a, Shape2 b) -> decltype(Collides(b, a)) {
return Collides(b, a);
}
// Or rename `Collides` into `CollidesImpl` and you can call this `Collides` instead
由于 ADL,这将考虑到未来的 Collides
功能。