Topic: Type deduction failure due to "invalid conversion" - where is it applicable?


Author: int19h@gmail.com
Date: Tue, 29 May 2007 11:02:18 CST
Raw View
14.8.2 p.2 of the Standard gives a list of reasons why type deduction
can fail, and among those is one that says, "Attempting to perform an
invalid conversion in either a template argument expression, or an
expression used in the function declaration.". The question is, what
exactly does it apply to? In particular, I have the following example
in my mind:


#include <iostream>
using namespace std;


template <size_t N>
struct Dummy
{
  Dummy(int)
  {
    cout << N << endl;
  }
};

template <class B, class D>
char Foo(Dummy<sizeof((B*)(D*)0)> = 0)
{
  return char();
}

struct char_char { char dummy[2]; };
template <class B, class D>
char_char Foo()
{
  return char_char();
}


struct A { };
struct B : A { };
struct C : A { };
struct D : B, C { };


int main()
{
  Foo<A, D>();
}


In this example, the expression ((B*)(D*)0), which occurs in a
function declaration, and is dependent on the template arguments of
the said function declaration, results in an invalid conversion for
Foo<A, D> specialization, since the cast from D* to A* is ambiguous.
Now, according to the wording of the Standard, should this trigger a
type substitution failure? If it does, SFINAE comes into play, and the
second overload of Foo should be silently chosen (which is obviously
what I want here); if it doesn't, the code just shouldn't compile. All
compilers I've checked so far fail to compile this, so I guess this
shouldn't work; but can someone please explain why the aforementioned
paragraph of the Standard does not apply here?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Greg Herlihy <greghe@pacbell.net>
Date: Thu, 31 May 2007 14:24:35 CST
Raw View
On 5/29/07 10:02 AM, in article
1180429650.255279.139890@m36g2000hse.googlegroups.com,
"int19h@gmail.com" <int19h@gmail.com> wrote:

> 14.8.2 p.2 of the Standard gives a list of reasons why type deduction
> can fail, and among those is one that says, "Attempting to perform an
> invalid conversion in either a template argument expression, or an
> expression used in the function declaration.". The question is, what
> exactly does it apply to? In particular, I have the following example
> in my mind:
>
> #include <iostream>
> using namespace std;
.
> template <class B, class D>
> char Foo(Dummy<sizeof((B*)(D*)0)> = 0)
> {
>   return char();
> }
>
> struct char_char { char dummy[2]; };
> template <class B, class D>
> char_char Foo()
> {
>   return char_char();
> }
>
> struct A { };
> struct B : A { };
> struct C : A { };
> struct D : B, C { };
>
> int main()
> {
>   Foo<A, D>();
> }
>
> In this example, the expression ((B*)(D*)0), which occurs in a
> function declaration, and is dependent on the template arguments of
> the said function declaration, results in an invalid conversion for
> Foo<A, D> specialization, since the cast from D* to A* is ambiguous.
> Now, according to the wording of the Standard, should this trigger a
> type substitution failure?

No, because the conversion from D* to A* is not invalid. On the
contrary, there are two valid conversions from D* to A*. So the
problem with the sample program is simply that a (valid) conversion
has been specified ambiguously - and not that the conversion itself is
invalid (which would be the case if no D* to A* conversion existed at
all).

Greg

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: jg <jgu222@gmail.com>
Date: Fri, 1 Jun 2007 18:24:11 CST
Raw View
On May 29, 10:02 am, int...@gmail.com wrote:
> 14.8.2 p.2 of the Standard gives a list of reasons why type deduction
> can fail, and among those is one that says, "Attempting to perform an
> invalid conversion in either a template argument expression, or an
> expression used in the function declaration.". The question is, what
> exactly does it apply to? In particular, I have the following example
> in my mind:
>
> #include <iostream>
> using namespace std;
>
> template <size_t N>
> struct Dummy
> {
>   Dummy(int)
>   {
>     cout << N << endl;
>   }
>
> };
>
> template <class B, class D>
> char Foo(Dummy<sizeof((B*)(D*)0)> = 0)
> {
>   return char();
>
> }
>
> struct char_char { char dummy[2]; };
> template <class B, class D>
> char_char Foo()
> {
>   return char_char();
>
> }
>
> struct A { };
> struct B : A { };
> struct C : A { };
> struct D : B, C { };
>
> int main()
> {
>   Foo<A, D>();
>
> }
>
> In this example, the expression ((B*)(D*)0), which occurs in a
> function declaration, and is dependent on the template arguments of
> the said function declaration, results in an invalid conversion for
> Foo<A, D> specialization, since the cast from D* to A* is ambiguous.
> Now, according to the wording of the Standard, should this trigger a
> type substitution failure? If it does, SFINAE comes into play, and the
> second overload of Foo should be silently chosen (which is obviously
> what I want here); if it doesn't, the code just shouldn't compile. All
> compilers I've checked so far fail to compile this, so I guess this
> shouldn't work; but can someone please explain why the aforementioned
> paragraph of the Standard does not apply here?
>

My guess is that Foo<A, D>() causes compiler to instantiate all
template Foo,
not just one. And when instantiating Foo(Dummy<sizeof((B*)(D*)0)> =
0), a
compiler finds the problem.  Not sure whether this is what the C++
standard
requires.

JG

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: int19h@gmail.com
Date: Sat, 9 Jun 2007 20:47:59 CST
Raw View
On 1 Jun, 00:24, Greg Herlihy <gre...@pacbell.net> wrote:

> No, because the conversion from D* to A* is not invalid. On the
> contrary, there are two valid conversions from D* to A*. So the
> problem with the sample program is simply that a (valid) conversion
> has been specified ambiguously - and not that the conversion itself is
> invalid (which would be the case if no D* to A* conversion existed at
> all).

Okay, here's another try. How about this:

#include <iostream>
using namespace std;

template <size_t N>
struct Dummy
{
  Dummy(int)
  {
    cout << N << endl;
  }
};

template <class B, class D>
char Foo(Dummy<sizeof(static_cast<D*>((B*)0))> = 0)
{
  return char();
}

struct char_char { char dummy[2]; };
template <class B, class D>
char_char Foo()
{
  return char_char();
}


struct A { };
struct D : virtual A { };


int main()
{
  cout << sizeof(Foo<A, D>()) << endl;
}

In this case, it would seem that a static_cast from A* to D* is a
nonambiguous and invalid conversion in this case. This didn't fare any
better when I tried it with real-world compilers, though. It went to
the point that one outright barked at the first definition of Foo,
complaining at the invalid use of static_cast for unrelated types,
even before it was instantiated (and indeed, even when it was not
instantiated at all)! Otherwise, the results were the same as with my
first code snippet.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]