|
Boost Users : |
Subject: Re: [Boost-users] function template argument deduction with std::tuple
From: Ireneusz SzczeÅniak (irek.szczesniak_at_[hidden])
Date: 2017-11-22 12:11:40
Gavin, thank you for your insightful answer! I think I understand
your arguments why the template argument deduction failed. I changed
my implementation, so that my type is derived from std::tuple. For
now I'm satisfied.
However, it bugs me that I'm still not sure whether I've implemented a
function-template specialization or a template for function
overloading. You claim that this is an overload:
> template <typename Graph>
> auto
> get_cost(const Label1<Graph> &l)
> {
> return std::get<0>(l);
> }
Could you please elaborate on how to tell one from the other? Had it
been a specialization, a compiler should accept the explicit template
argument:
> template <typename Graph>
> auto
> get_cost<Label1<Graph>>(const Label1<Graph> &l)
> {
> return std::get<0>(l);
> }
but I get (with gcc version 7.2.0):
> error: non-class, non-variable partial specialization
> âget_cost<Label1<Graph> >â is not allowed
> get_cost<Label1<Graph>>(const Label1<Graph> &l)
So it seems that I was defining overloads (these don't have template
arguments), not specializations as I thought. The C++ Programming
Language, 4th edition, the bottom of page 737, says that you can drop
the explicit template argument in the definition of a template
specialization, if it can be deduced. So I dropped the explicit
template argument, and still considered the definition the specialization.
I have a hard time understanding the above error message, thought. I
understand that "non-class" simply means that it's not a member
function, OK. But what "non-variable partial specialization" could
possibly mean? What is "non-variable" here, and why "partial
specialization" when I gave all (i.e., one) template argument. I
consider it a complete specialization albeit dependent on a template
parameter Graph.
On 17.11.2017 00:12, Gavin Lambert via Boost-users wrote:
> 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 mailing list
> Boost-users_at_[hidden]
> https://lists.boost.org/mailman/listinfo.cgi/boost-users
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