Binary Operator for Template Class Doesn't Resolve Implicit Conversion

你离开我真会死。 提交于 2019-12-24 10:00:00

问题


Consider the following classes, where the first is templated. Both are meant to hold a numeric value.

template<typename T>
struct foo
{
    foo(T val) : val{ val } {}
    T val;
};

struct bar
{
    bar(double val) : val{ val } {}
    double val;
};

I want to define a way to add these classes together to get a new one with a different value.

template<typename T>
foo<T> operator+(foo<T> a, foo<T> b)
{
    return foo<T>(a.val + b.val);
}

bar operator+(bar a, bar b)
{
    return bar(a.val + b.val);
}

When I use these operators with implicit conversion, the operator using object of type foo doesn't use the implicit conversion on the double value to apply my overloaded operator, even though it can do it for the non-template class. The result is that there is no operator matching the types in that expression.

int main()
{
    foo<double> foo_value(11.0);
    bar bar_value(11.0);

    foo<double> ev1 = foo_value + 1.0; // no operator matches these operands
    bar ev2 = bar_value + 1.0;
}

Does the operator have to be explicitly instantiated first? If so, a) how does that look like, and b) why isn't the instantiation done implicitly, if it can be done when initializing an object of type foo<double>?

If the standard doesn't support any sort of resolution without explicitly casting 1.0 to a value of type foo<double>, I presume the only other possibility is defining operator overloads for each type I want to use like that (for both lhs and rhs)?


回答1:


The thing you have to remember about templates is that they will not do a conversion for you. All they do is try and figure out the types things are, and if that jives with template parameters, then it will stamp out the function and call it.

In you case when you do

foo_value + 1.0

the compiler goes okay, lets see if we have any operator + that will work for this. It finds

template<typename T>
foo<T> operator+(foo<T> a, foo<T> b)
{
    return foo<T>(a.val + b.val);
}

and then it tries to figure out what T is so it can stamp out a concrete function. It looks at foo_value, sees it is a foo<double> so it says for the first parameter T needs to be a double. Then it looks at 1.0 and goes okay, I have a double and that is when you run into a problem. The compiler can't deduce what T should be for b because it expects a foo<some_type>, but got a double instead. Because it can't deduce a type, your code fails to compile.

In order to get the behavior you want you would need to add

template<typename T>
foo<T> operator+(foo<T> a, T b)
{
    return foo<T>(a.val + b);
}

Which lets you add a T to a foo<T>, or better yet

template<typename T, typename U>
foo<T> operator+(foo<T> a, U b)
{
    return foo<T>(a.val + b);
}

Which lets you add anything to a foo<T> (foo<double> + int for instance where the first version would not allow that)



来源:https://stackoverflow.com/questions/56262451/binary-operator-for-template-class-doesnt-resolve-implicit-conversion

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!