Search code examples
c++sfinaeenable-if

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


I have a class defined as:

template <typename V, typename E>
class AdjacencyList;

Where V and E are the types of the vertex and edge values respectively.

I am currently attempting to define the following member function inside AdjacencyList:

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

For those familiar with Dijkstra's algorithm, it is only possible to implement correctly if E is an addable and non-negative type. Therefore, how do I correctly use the enable_if construct to only enable this function if E is an unsigned integral type?

I am currently seeing two complications here that I am uncomfortable with approaching:

  1. Both the return type and the parameter concern E.
  2. E itself is not used as a type, but is used in other type templates.

Because I am relatively new to the enable_if construct, I would feel more comfortable with some guidance on the issue since this is a relatively non-trivial case.


Solution

  • This is not actually what you want to do.

    The point of std::enable_if is to cause substitution failure for a template. The reason why you want substitution failure is because it's not a failure, and you can select a different overload instead. However, there's no point here because you're not trying to choose a different overload, you're just trying to make it a failure.

    So, you'd instead do something like this:

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

    If you try to call this function with the wrong type of arguments, you get a nice compile-time error telling you that E must be addable and non-negative. If you used enable_if instead, you'd get an error that none of the overloads were valid, which is a less informative error.

    This is probably a bad design, though. Ordinarily you would just throw an exception if you encountered a negative value. Choosing to enforce that the inputs are positive is also incomplete, since the algorithm will also fail if you encounter overflow.

    (If you really want to do enable_if even though it's a bad idea, you can..)

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

    If you actually want to program this way

    C++ is the wrong language for this type of programming, and hammering C++ until it works this way will result in some very bizzare C++ code. It sounds like you actually want to write code in Agda.