1

I don't quite understand why this code here does not compile. It should be possible to call dist() like so:

dist(GenericVec2<T>,GenericVec3<T>)

(However horrible this may be). The idea is that the GenericVec3 argument gets implicitly converted into a GenericVec2 by the conversion operator. I found this question here

C++ implicit type conversion with template

, but I'm not so sure if it can be applied to my problem (setting the conversion operator to "friend" didn't work). VS outputs the following error:

error C2672: 'dist': no matching overloaded function found
error C2784: 'F dist(const GenericVec2<F> &,const GenericVec2<F> &)': could not deduce template argument for 'const GenericVec2<F> &' from 'Vec3'
note: see declaration of 'dist'

Here is my code:

#include <iostream>

template<typename F> struct GenericVec2
{
    GenericVec2<F>::GenericVec2(F _x = 0, F _y = 0) : x(_x), y(_y) {}

    F x;
    F y;
};
using Vec2 = GenericVec2<float>;

template<typename F> struct GenericVec3
{
    GenericVec3<F>::GenericVec3(F _x = 0, F _y = 0, F _z = 0) : x(_x), y(_y), z(_z) {}

    operator GenericVec2<F>()               { return *reinterpret_cast<GenericVec2<F>*>(&x); }
    operator const GenericVec2<F>() const   { return *reinterpret_cast<const GenericVec2<F>*>(&x); }

    F x;
    F y;
    F z;
};
using Vec3 = GenericVec3<float>;

template<typename F> F dist(const GenericVec2<F>& a, const GenericVec2<F>& b)
{
    return std::hypot(a.x - b.x, a.y - b.y);
}

int main()
{
    Vec2 a{ 2.0f, 3.0f };
    Vec3 b{ 1.0f, 1.0f, 1.0f };
    Vec2 c = b;

    float d = dist(a, Vec2{ b });   // works
    float e = dist(a, b);           // doesn't compile

    std::cin.ignore();

    return 0;
}

Thanks in advance!

-Thomas

Thomas B.
  • 691
  • 4
  • 15
  • 2
    Your `reinterpret_cast` breaks strict aliasing and reading from a `union` member other than the one last assigned to is also UB. Throw that code away and start from scratch, it is broken beyond repair. If you don't see why I'm saying this, it's time to read a good book. – Baum mit Augen May 31 '17 at 10:41
  • I can't, it's not my code and not easily exchanged. I just need to know how to get it to compile (ideally without doing the explicit `dist(a, Vec2{b})` conversion. – Thomas B. May 31 '17 at 10:51
  • I have removed the union, as it wasn't part of the actual problem (and indeed not very pretty). Originial question still stands. – Thomas B. May 31 '17 at 10:57
  • In case that was not clear in my first comment: This code is plain incorrect and illegal. Making it compile will not make it better *at all*. This code can not be used, neither in production, POC nor toy programs. (Still applies after the `union` was removed, see strict aliasing.) – Baum mit Augen May 31 '17 at 10:58
  • You can't combine user-defined implicit conversions with template argument deduction. `dist(a, b)` should also work. – aschepler May 31 '17 at 11:35
  • Understood, thank you very much! – Thomas B. May 31 '17 at 11:54

2 Answers2

0

To implicit conversion be possible the target class shall have a constructor that receives the source type (or a type convertible from a source type) as a parameter. The casting operator as defined in GenericVec3 is used in explicit casting operations.

So you should define the following constructor in your GenericVec2 class

GenericVec2(const GenericVec3<F>& v3) { ... }

Eugene
  • 2,858
  • 1
  • 26
  • 25
0

Problem is that, in

template<typename F> F dist(const GenericVec2<F>& a, const GenericVec2<F>& b)

you cannot deduced second parameter from GenericVec2<float>. One solution is to make the function non template thanks to friend:

template<typename F> struct GenericVec2
{
    GenericVec2<F>::GenericVec2(F _x = 0, F _y = 0) : x(_x), y(_y) {}


    friend F dist(const GenericVec2& a, const GenericVec2& b)
    {
        return std::hypot(a.x - b.x, a.y - b.y);
    }

    F x;
    F y;
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302