【问题标题】:How to multiply objects of different template type in C++如何在 C++ 中将不同模板类型的对象相乘
【发布时间】:2015-04-04 08:34:52
【问题描述】:

我怎样才能使(使用不同模板类型的对象)A*B 和 B*A 给出相同的结果,结果的类型是根据通常的 C++ 类型提升规则确定的?

例如:

int main()
{
    number<float> A(2.0f);    
    number<double> B(3.0);
    A*B; // I want 6.0 (double)
    B*A; // I want 6.0 (double)

    return 0;
}

目前,我只能将相同模板类型的对象相乘。例如,像这样:

template<typename T>
class number
{
    public:

        number(T v) : _value(v) {}

        T get_value() const { return _value; }

        number& operator*=(const number& rhs)
        {
            _value *= rhs.get_value(); 
            return *this;
        } 

    private:

        T _value;
};

template<typename T>
inline number<T> operator*(number<T> lhs, const number<T>& rhs)
{
  lhs *= rhs;
  return lhs;
}

编辑:或者,如答案所示,我可以将不同模板类型的对象相乘,但总是返回与 lhs 相同的类型。有什么方法可以返回一个类型由标准类型提升规则确定的对象?

编辑 2:如果可能,我想避免使用 C++11 功能

【问题讨论】:

  • 为什么要避开 c++11 的特性?
  • 因为我不确定我在各个地方使用的任何/部分/所有工具链是否可以构建 C++11 代码,我不知道进行转换是多么痛苦。如果 C++11 是必要的,那么我将开始下载升级,这样我就可以进行排序了。
  • 使用 C++11 很容易(请参阅我的回答),但我不知道使用 C++03 的解决方案(老实说,寻求解决方案没有意义)。
  • 你使用什么编译器? Clang、GCC、英特尔编译器、VisualStudio 和 XCode(基于 clang)已经支持 C++11 多年(VS 支持并不完整,但对于手头的问题来说已经足够完善了)。此外,几乎所有仍受支持的 linux 发行版上的默认编译器 (gcc) 都应该支持必要的 c++11 特性子集。但即使你的一个编译器不支持它,我认为完成一次更新过程比坚持使用 pre c++11 代码更容易。
  • 我主要使用 GCC,但偶尔必须使用 Visual Studio。我已经整理好这台笔记本电脑(它很轻松),并会在我使用其他电脑时处理它们。这两个答案都非常好用,但目前我使用的是common_type,因为它似乎更直接一些。

标签: c++ templates operator-overloading


【解决方案1】:

你必须模板化,例如rhs参数:

template<typename T>
class number
{
public:

    number(T v) : _value(v) {}

    T get_value() const { return _value; }
    template<class E>
    number& operator*=(const number<E>& rhs)
    {
        _value *= rhs.get_value(); 
        return *this;
    } 

private:

    T _value;
};

template<class T, class E, class RET = decltype(T()*E())>
number<RET> operator*(number<T>& lhs, const number<E>& rhs)
{
    return lhs.get_value()*rhs.get_value();
}

【讨论】:

  • @Harry:我将operator* 更改为一个版本,它总是会返回正确的类型。
  • 谢谢,这看起来很有希望。我会进行一些升级,然后试一试。
  • 这似乎可行,但我实际上并不了解它是如何编译的。我觉得应该return number&lt;RET&gt;(lhs.get_value()*rhs.get_value()); ...在您的版本中,我不明白它如何转换为number&lt;RET&gt;
  • @Harry:由于number的构造函数不是explicit,所以乘法的结果隐式转换为输出数据类型,当然你也可以显式转换。
【解决方案2】:

您可以使用std::common_type&lt;&gt;获取返回所需的类型。例如

template<typename X>
struct number
{
  // ...

  template<typename Y>
  number(number<Y> const&other);              // needed in line 1 below

  template<typename Y>
  number&operator=(number<Y> const&other);    // you may also want this

  template<typename Y>
  number&operator*=(number<Y> const&other);   // needed in line 2 below

  template<typename Y>
  number<typename std::common_type<X,Y>::type> operator*(number<Y> const&y) const
  {
    number<typename std::common_type<X,Y>::type> result=x;   // 1
    return result*=y;                                        // 2
  }
};

我省略了模板化构造函数和 operator*= 的实现。


不幸的是,std::common_type 是 C++11,出于不明原因,您希望避免使用它。如果您只使用内置类型(doublefloatint 等),您可以轻松实现自己的 common_type 版本。但是,如果您想做复杂的元模板编程,强烈建议您继续使用 C++11——它已经 4 岁了,而且大部分都向后兼容。

【讨论】:

  • 感谢您的建议。我会进行一些升级并看看这个。
【解决方案3】:

operator*() 需要一个模板化的重载

template<typename T>
class number {
    public:
    // ...
    template<typename U>
    number& operator*=(const number<U>& rhs) {
        // ...
    }
    // ...
 };

二元运算符也是如此

template<typename T,typename U>
inline number<T> operator*(number<T> lhs, const number<U>& rhs) {
  lhs *= rhs;
  return lhs;
}

【讨论】:

  • 仅此还不够,您还必须为重载的*-operator 引入第二个模板参数
  • @MikeMB 这正是我的提议?
  • 不仅是一元number&amp; operator*=(const number&lt;U&gt;&amp; rhs),还有二元number&lt;T&gt; operator*(number&lt;T&gt; lhs, const number&lt;T&gt;&amp; rhs)
  • 但是这总是返回类型 T 而从不输入 U。我真正感兴趣的部分是如何获得正确的返回类型。例如,我想要 2.0f * 3.0 == 3.0 * 2.0f == 2.0 * 3.0f == 3.0f * 2.0 == 6.0(双倍)。这可能吗?
  • 如果要返回U,在返回类型声明中切换即可?
猜你喜欢
  • 2011-10-31
  • 1970-01-01
  • 2016-11-30
  • 1970-01-01
  • 1970-01-01
  • 2021-04-15
  • 1970-01-01
  • 2013-04-26
  • 2019-12-19
相关资源
最近更新 更多