如何在此特定函数声明中正确使用enable_if?

时间:2017-04-26 06:22:49

标签: c++ sfinae enable-if

我有一个定义为:

的类
template <typename V, typename E>
class AdjacencyList;

其中V和E分别是顶点和边缘值的类型。

我目前正在尝试在AdjacencyList中定义以下成员函数:

std::map< std::shared_ptr< Vertex<V, E> >, E > dijkstra(
    const std::shared_ptr< Vertex<V, E> > &start_vertex) const;

对于那些熟悉Dijkstra算法的人来说,只有E是可添加和非负类型才能正确实现。因此,如果enable_if是无符号整数类型,如何正确使用E构造才能启用此函数?

我目前看到两种并发症,我对接近感到不舒服:

  1. 返回类型和参数都关注E
  2. E本身不用作类型,但在其他类型模板中使用。
  3. 因为我对enable_if构造相对较新,所以我会对这个问题的一些指导感到更自在,因为这是一个相对不重要的案例。

3 个答案:

答案 0 :(得分:1)

如果要编写具有调整类型要求的多个重载,

enable_if会很有用。在您的情况下,您没有任何重载,只想强制执行某些类型限制。因此,您可以使用static_assert来检查它们,并为用户提供有意义的诊断消息,而不是通常的模板实例化故障。像这样:

<type_traits>
<utility>

...

static_assert(::std::is_unsigned< E >::value, "edge value type must be unsigned integral type");
static_assert(::std::is_same< E, decltype(::std::declval< E >() + ::std::declval< E >()) >, "edge value type must be addable");

答案 1 :(得分:1)

  

如果E是无符号整数类型

,则仅启用此函数

我按原样收到您的评论/请求,并直接使用<type_traits>提供的工具 如果您想使用std::enable_if,可能以下内容对您来说几乎没问题:

std::enable_if_t<std::is_integral<E>::value and std::is_unsigned<E>::value, std::map< std::shared_ptr< Vertex<V, E> >, E >> dijkstra( const std::shared_ptr< Vertex<V, E> > &start_vertex) const;

无论如何,SFINAE( S ubstitution F ailure I s N ot A n E rror)是有意义的,否则你正在做一些我们可以调用的东西 S ubstitution F ailure s A lways A n E rror。在这些情况下,static_assert更合适:

static_assert(std::is_integral<E>::value and std::is_unsigned<E>::value, "!");

将它作为功能的第一行。带有静态断言的错误消息通常也更加用户友好。

答案 2 :(得分:1)

这实际上并不是你想要做的。

std::enable_if的要点是导致模板的替换失败。您希望替换失败的原因是因为它不是失败,您可以选择不同的重载。但是,这里没有意义,因为您并没有尝试选择不同的重载,而是只是试图让它失败。

所以,你做了类似的事情:

std::map< std::shared_ptr< Vertex<V, E> >, E > dijkstra(
    const std::shared_ptr< Vertex<V, E> > &start_vertex) const {
    static_assert(
        std::is_unsigned<E>::value,
        "E must be unsigned.");
}

如果尝试使用错误类型的参数调用此函数,则会得到一个很好的编译时错误,告诉您E必须是可添加的且非负的。如果您使用了enable_if,则会收到错误,其中没有任何重载是有效的,这是一个信息量较小的错误。

但这可能是一个糟糕的设计。通常,如果遇到负值,则只会抛出异常。选择强制输入是肯定的也是不完整的,因为如果遇到溢出,算法也会失败。

(如果你真的想做enable_if,即使这不是一个坏主意,你可以......)

std::enable_if<std::is_unsigned<E>,
               std::map<std::shared_ptr<Vertex<V, E>>, E>::type dijkstra...

如果你真的想以这种方式编程

对于这种类型的编程来说,C ++是错误的语言,并且在使用这种方式之前锤击C ++将导致一些非常古怪的C ++代码。听起来你真的想在Agda中编写代码。