【问题标题】:Choose correct return type of template member function选择模板成员函数的正确返回类型
【发布时间】:2018-11-27 07:46:26
【问题描述】:

我有一个看起来像这样的模板类:

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>

【问题讨论】:

  • std::common_type怎么样?
  • 如果std::common_type 不(或不总是)提供所需的类型,您可以提供自己的专业。
  • 这就是我要找的!谢谢!
  • @aCuria:您可以自行回答这个问题,以便对其他人有用。

标签: c++ class c++11 templates return-type


【解决方案1】:

正如 @Someprogrammerdude 在 cmets 中提到的那样,使用 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

【讨论】:

【解决方案2】:

我个人倾向于decltype(std::declval&lt;T&gt;() / std::declval&lt;U&gt;()) 而不是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;
    }
};

【讨论】:

  • 这只对除法有用吗? decltype(std::declval() / std::declval() 实际上是做什么的?
  • @aCuria 它“模拟”将T 类型的值除以U 类型的值,并查看将返回的类型。您可以通过这种方式在decltype 中编写(几乎)任何表达式,因此它适用于所有运算符。
  • 我明白了,这对于短 * 短这样的情况确实有所不同。 std::common_type 会输出一个 short,而 decltype 会给你一个 int。
  • @Quentin 但这提出了一个问题,应该(在现实生活中)返回Mtx&lt;short&gt; 的函数的常见返回类型是什么?当我使用你所说的尾随返回类型时,我看到了这种变化。这就是我没有添加soln的原因。
  • @JeJo 公平的整数促销模仿了 C 中的那些,而且并非所有相关人员都认为它们有用。我个人怀疑它是否会成为今天设计的语言的一部分,但我倾向于坚持将一致性作为第一个默认设置。如果有人说“整数促销很愚蠢,我不会使用它”,我不会生气:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-05
  • 1970-01-01
  • 2019-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多