简体   繁体   中英

Choose correct return type of template member function

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>

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM