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++ 中可能吗?
我想做的是
Run Code Online (Sandbox Code Playgroud)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);
即选择重载取决于模板参数是否具有特定成员。在 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()函数集中删除此重载版本。