Reputation: 7205
I have a template class that looks like this:
template <typename T, std::size_t M, std::size_t N> // MxN matrix with elements of type T
struct Mtx{...}
// component wise division
template <typename U> Mtx operator/(const Mtx<U, M, N> &rhs) const
{ return componentDivide(*this, rhs); }
What is the best way to ensure that the return type of functions like operator /
is "correct"?
eg:
Mtx<float> * Mtx<unsigned> = Mtx<float>
Mtx<float> * Mtx<int> = Mtx<float>
Mtx<float> * Mtx<double> = Mtx<double>
Mtx<double> * Mtx<float> = Mtx<double>
Mtx<short> * Mtx<int> = Mtx<int>
Upvotes: 3
Views: 151
Reputation: 63124
I'd personally lean on the side of decltype(std::declval<T>() / std::declval<U>())
rather than std::common_type
, because it explicitly chooses the type to mirror an actual division.
Thus:
template <typename T>
struct Mtx
{
T _var;
template <typename U>
Mtx<decltype(std::declval<T>() / std::declval<U>())>
operator / (const Mtx<U> &rhs) const
{
return this->_var / rhs._var;
}
};
Or, by using a trailing return type so we can express it with the parameters' types:
template <typename T>
struct Mtx
{
T _var;
template <typename U>
auto operator / (const Mtx<U> &rhs) const
-> Mtx<decltype(this->_var / rhs._var)>
{
return this->_var / rhs._var;
}
};
Upvotes: 2
Reputation: 32797
As @Someprogrammerdude mentioned in the comments using std::common_type
should work for what you want.
#include <iostream>
#include <type_traits>
template <typename T> struct Mtx
{
T _var;
template <typename U>
Mtx<std::common_type_t<T, U>> operator/(const Mtx<U> &rhs) const
{
return this->_var/rhs._var;
}
};
int main()
{
Mtx<float> fObj{ 1.02f };
Mtx<unsigned> uObj{ 1 };
Mtx<int> iObj{ 1 };
Mtx<double> dObj{ 1.02 };
Mtx<short> sObj{ 1 };
std::cout << std::boolalpha
<< std::is_same_v< decltype(fObj / uObj), Mtx<float>> << '\n' // Mtx<float> * Mtx<unsigned> = Mtx<float>
<< std::is_same_v< decltype(fObj / iObj), Mtx<float>> << '\n' // Mtx<float> * Mtx<int> = Mtx<float>
<< std::is_same_v< decltype(fObj / dObj), Mtx<double>> << '\n' // Mtx<float> * Mtx<double> = Mtx<double>
<< std::is_same_v< decltype(dObj / fObj), Mtx<double>> << '\n' // Mtx<double> * Mtx<float> = Mtx<double>
<< std::is_same_v< decltype(sObj / iObj), Mtx<int>> << '\n'; // Mtx<short> * Mtx<int> = Mtx<int>
return 0;
}
Output:
true
true
true
true
true
Upvotes: 3