基于条件的模板重载

Ole*_*ksa 1 c++ templates overloading metaprogramming template-meta-programming

使用类型特征,我可以执行以下操作:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

template<typename Rect, typename Size> Rect& move(Rect& rc, Size delta);
template<typename Rect, typename Point> Rect& move(Rect& rc, Point to);
Run Code Online (Sandbox Code Playgroud)

我想做的是

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);
Run Code Online (Sandbox Code Playgroud)

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

max*_*x66 6

我想做的是

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

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

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

我的意思是......

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
Run Code Online (Sandbox Code Playgroud)

显然,如果您move()使用带有 awith和 ax成员的第二个参数进行调用,这将不起作用:编译器不知道move()选择了哪一个。

这个怎么运作?

很简单:主要词是 SFINAE,这意味着替换失败不是错误。

接受decltype()返回所包含表达式类型的计数,因此(例如)从

   decltype( size.width, rc );
Run Code Online (Sandbox Code Playgroud)

逗号运算符 discard size.width如果 可用(这是重要的一点!),并保留rc,因此decltype()返回rc(如果size.width存在!)的类型。

但是如果size.width不存在会发生什么?

你有一个“替代失败”。那“不是错误”,而是move()从可用move()函数集中删除此重载版本。