Boost logo

Boost Users :

Subject: Re: [Boost-users] function template argument deduction with std::tuple
From: Gavin Lambert (gavinl_at_[hidden])
Date: 2017-11-16 23:12:01


On 16/11/2017 21:33, Ireneusz Szcześniak wrote:
> Thanks for your email.  However, I wonder why the other specializations
> are used, and not the one for type Label.  If your reasoning was
> correct, the code for other specializations (for Label1, Label2, Label3)
> would fail to compile too.

In your original post, you don't have any specialisations -- just
overloads. They are not the same thing.

> My guess is that for some season a compiler does not consider the
> specialization of get_cost for type Label, and reverts to the get_cost
> declaration, thus complaining that the type for auto cannot be deduced
> simply because there is no definition of the function.  There might be
> some interplay between function overloading and function template
> specialization.

That's true; I didn't try linking so didn't notice that it was indeed
still selecting the T overload instead of the Label<Graph> overload.

I think the issue here is that as Label is an alias, the compiler has
trouble deducing things about it:

   1. To the compiler, "l" is a variable with type std::tuple<unsigned>.
   2. When calling get_cost, it has to choose between several overloads
-- the Label1/2/3 overloads can obviously be excluded, because
std::tuple is not those types. So the choice is between T and
std::tuple<Vertex<Graph>>.
   3. Vertex<Graph> is also an alias, though, so that is actually
std::tuple<Graph::vertex_descriptor>.
   4. When matching std::tuple<unsigned> to
std::tuple<Graph::vertex_descriptor>, it does not know what type Graph
is and it cannot infer it from the parameter alone, so cannot resolve
what Graph::vertex_descriptor might be.
   5. So it must choose T.

Note that the existence of the T overload doesn't influence this -- if
you comment it out then it will still fail because it still can't deduce
what Graph should be purely from the arguments.

The Label1/2/3 overloads work because the parameter type is actually
Label1<graph> (a real type, not just an alias), and so when matching
const Label1<Graph>& it is able to deduce that Graph=>graph. Once it
knows that then it can find graph::vertex_descriptor.

You can make it work by forgoing the deduction and specifying the Graph
type explicitly:

     get_cost<graph>(l);

This forces it to exclude the generic T overload because l isn't a const
graph&, so it will match the const Label<graph>& overload instead.

Another option is to pass a Graph object as an additional parameter
directly; this will allow its type to be deduced and then it will be
able to determine that Graph::vertex_descriptor is an unsigned, and
match the overload.

Still another option is to make Vertex a "real" type; this will make the
parameter std::tuple<Vertex<graph>> and again it will be able to match
this by deducing Graph.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net