简体   繁体   中英

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.

enable_if is helpful if you want to write several overloads with adjusted type requirements. In your case you don't have any overloads and only want to enforce some type restrictions. So you can just use static_assert to check them and give user a meaningful diagnostic message instead of usual template instantiation failure mess. Something like this:

<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

I get your comment/request as it is and use directly the tools provided by <type_traits> .
If you want to use std::enable_if , probably the following works almost fine for you:

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;

Anyway, SFINAE ( S ubstitution F ailure I s N ot A n E rror) makes sense when you have more than one option, otherwise you are doing something we can call S ubstitution F ailure I s A lways A n E rror. In these cases, a static_assert is more appropriate:

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

Put it as the very first line of your function. Error messages with static asserts are also usually more user friendly.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM