Выберите правильный тип возврата функции-члена шаблона - PullRequest
0 голосов
/ 27 ноября 2018

У меня есть шаблон класса, который выглядит следующим образом:

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

Каков наилучший способ гарантировать, что возвращаемый тип функций, таких как operator /, является "правильным"?

например:

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>

Ответы [ 2 ]

0 голосов
/ 27 ноября 2018

Я бы лично опирался на decltype(std::declval<T>() / std::declval<U>()), а не std::common_type, потому что он явно выбирает тип для отражения фактического деления.

Таким образом:

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

Или, используя конечный тип возврата, чтобы мы могли выразить его с типами параметров:

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;
    }
};
0 голосов
/ 27 ноября 2018

Как @Someprogrammerdude, упомянутый в комментариях, использование std::common_type должно работать на то, что вы хотите.

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

Вывод :

true
true
true
true
true
...