c++ 约束模板参数是不是一个坏习惯?

hpxqektj  于 2023-10-21  发布在  其他
关注(0)|答案(1)|浏览(138)

在C++中,假定模板参数具有根据此源的某些字段或方法是法律的。如果它不这样做,它将简单地无法编译。

template<class Container>
void draw_all(Container& c)
{
    for_each(c.begin(),c.end(),mem_fun(&Shape::draw));
}

在这个例子中,Container必须实现begin()end()才能编译程序。然而,看看函数的原型,似乎没有这样的限制。
换句话说,关于接口使用的信息与实现交织在一起(即使使用static_assert)。
在我看来,这似乎是一种糟糕的做法(尽管我自己也遇到过这种情况,但这仍然是我能找到的最优雅的解决方案)。如果不是,使用它的理由是什么?

hujrc8aj

hujrc8aj1#

在C20之前,这就是我们所拥有的一切。有一件事你不能从C20之前的C模板中拿走,那就是它们允许很大的灵活性(在某些情况下可能需要),并且在某种程度上允许API提供者和API消费者之间的隐式契约。
C
20沿着出现,并引入了concepts,几乎是为了解决由于契约的松散而导致的问题。
现在,该函数可能被写为:

template <class Container>
concept DrawableContainer = requires (Container c) {
  { c.begin() };
  { c.end() };
  { *(c.begin()) } -> std::convertible_to<typename Container::value_type>;
  requires std::invocable<decltype(&Shape::draw), decltype(*(c.begin()))>;
  // Plus whatever else constraints are needed
};

void draw_all(DrawableContainer auto& c)
{
    for_each(c.begin(),c.end(),mem_fun(&Shape::draw));
}

这仍然允许相同的灵活性,但具有更好的文档化功能,即使只使用代码。
如果您无法访问概念,那么没有比一个好的旧模板更好的解决方案了。您可以尝试在任何地方使用SFINAE,使其更容易使用。

相关问题