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

How do I correctly use enable_if in this specific function declaration?

我有一个 class 定义为:

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是可加非负类型才有可能正确实现。因此,如果 E 是无符号整数类型,我该如何正确使用 enable_if 构造来启用此功能?

我目前在这里看到两个并发症,我不太愿意接近:

  1. return类型和参数都关注E
  2. E本身不作为类型使用,而是在其他类型模板中使用。

因为我对 enable_if 结构比较陌生,所以我会更愿意接受关于这个问题的一些指导,因为这是一个相对重要的案例。

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");

only enable this function if E is an unsigned integral type

我把你的comment/request照原样拿到了,直接用<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替换 F失败 Is Not An Error) 当你有多个选项时才有意义,否则你正在做一些我们可以称之为S替换F失败IsAlwaysAn E错误。在这些情况下,static_assert 更合适:

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

把它放在函数的第一行。带有静态断言的错误消息通常也更加用户友好。

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

std::enable_if的重点是导致模板替换失败。你想要替换失败的原因是因为它不是失败,你可以 select 一个不同的重载。但是,这里没有意义,因为您不是在尝试选择不同的重载,您只是在尝试使其失败。

所以,您应该这样做:

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,则会收到一个错误,指出 none 个重载有效,这是一个信息量较少的错误。

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

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

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

如果你真的想这样编程

C++ 是这种类型的编程的错误语言,并且不断敲打 C++ 直到它以这种方式工作将导致一些非常奇怪的 C++ 代码。听起来你真的想在 Agda 中编写代码。