Search code examples
c++templatesimplicit-conversionconversion-operator

Implicit conversion between templates


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


Solution

  • 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;
    };