基于条件的模板重载

Template overload based on condition

有了类型特征,我可以执行以下操作:

template<typename Rect> Rect& move(Rect& rc, size_type<Rect> delta)
{
    rc.left += delta.width;
    rc.right += delta.width;
    rc.top += delta.height;
    rc.bottom += delta.height;
    return rc;
}
template<typename Rect> Rect& move(Rect& rc, point_type<Rect> to)
{
    int w = w(rc);
    int h = h(rc);
    rc.left = to.x;
    rc.top = to.y;
    rc.right = rc.left + w;
    rc.bottom = rc.top + h;
    return rc;
}

但是我怎样才能允许在不更改函数名称的情况下传递任何大小和点类型?显然我不能这样做:

template<typename Rect, typename Size> Rect& move(Rect& rc, Size delta);
template<typename Rect, typename Point> Rect& move(Rect& rc, Point to);

我想做的是

template<typename Rect, typename Size /*if Size::width, use this*/> Rect& move(Rect& rc, Size size);
template<typename Rect, typename Point /*if Point::x, use this*/> Rect& move(Rect& rc, Point to);

即选择重载取决于模板参数是否具有特定成员。在 C++ 中可以吗?

What I want to do is

template<typename Rect, typename Size /*if Size::width, use this*/>
Rect& move(Rect& rc, Size size);
template<typename Rect, typename Point /*if Point::x, use this*/> 
Rect& move(Rect& rc, Point to);

I.e. choosing an overload depends on whether a template argument has a particular member. Is it possible in c++?

如果您至少可以使用 C++11...您是否通过尾随 return 类型和 decltype() 尝试使用 SFINAE?

我的意思是……

template <typename Rect, typename Size>
auto move (Rect & rc, Size size)
   -> decltype( size.width, rc );
// .............^^^^^^^^^^^  <-- note this

template <typename Rect, typename Point> 
auto move(Rect& rc, Point to)
   -> decltype( to.x, rc );
// .............^^^^^  <-- and note this

显然,如果您使用带有 withx 成员的第二个参数调用 move(),这显然不起作用:编译器不知道哪个 move() select.

它是如何工作的?

很简单:主词是SFINAE,意思是Substitution Failure Is Not An Error。

考虑 decltype() return 包含的表达式的类型,因此(例如)来自

   decltype( size.width, rc );

逗号运算符丢弃 size.widthif available(这是重点!),并保留 rc,所以 decltype() return rc 的类型(如果 size.width 存在!)。

但是如果 size.width 不存在会怎样?

您遇到了“替换失败”。那“不是错误”,而是从可用的 move() 函数集中删除 move() 的这个重载版本。