【问题标题】:warning C4244: 'argument' : conversion from 'double' to 'const int', possible loss of data警告 C4244:'argument':从 'double' 转换为 'const int',可能丢失数据
【发布时间】:2013-08-31 21:13:26
【问题描述】:

我正在定义“*”运算符以使用“NumericArray”类模板。代码如下:

template <class T>
NumericArray<T> NumericArray<T>::operator * (const T& factor) const
{
    NumericArray<T> newArray(Size());
    for (int i = 0; i < Size(); i++)
        newArray[i] = factor * GetE(i);
    return newArray;
}

当“因子”参数为双精度时,当我尝试将“int”(NumericArray)类型的“NumericArray”与“*”运算符一起使用时:

intArray1 = intArray1*2.5;

我收到以下编译器警告:

warning C4244: 'argument' : conversion from 'double' to 'const int', possible loss of data

并且“因子”arg 在与“NumericArray”对象的元素相乘之前从 2.5 截断为 2(一个 int)。有没有办法防止这种情况发生?我认为在 C++ 中这是一个简单的默认协议问题,其中 int*double = double。我错了吗?如果不是,为什么在这种情况下不适用?

【问题讨论】:

  • +1 对于新用户来说,这是一个简单但有价值的问题。模板不是小事!

标签: c++


【解决方案1】:
intArray1 = intArray1*2.5;

我猜 intArray1 的类型是 NumericArray&lt;int&gt; 。如果是这样,那么T 就是int。所以在上面的表达式中,2.5 是一个double 将被转换为int,因为它作为参数传递给重载的operator*(const int&amp;)

这也意味着,2.5 (double) 变成 2 (int) 而factor 基本上是2。数据丢失!

解决此问题的一种方法是将函数模板(作为类模板的成员)用作:

template<class T>   //this is for class templatwe
template<class U>   //this is for function template
NumericArray<T> NumericArray<T>::operator * (const U& factor) const
{                                           //^^^^^^^ it is U now!
     //your code
}

不要对上述定义中template 的两次用法感到惊讶。 cmets 说他们的目的。如果你理解得很好,那么你也明白参数 nowU 而不是T,它可以独立于T,因此它可以是你传递给它的任何东西争论。在传递参数时不会丢失数据。

既然你知道intdouble 的乘积结果是double,那么为什么在你将double 传递给它的情况下从函数中返回NumericArray&lt;int&gt;?如果参数是double,我认为返回NumericArray&lt;double&gt; 更有意义。所以下面的似乎是正确的实现:

template<class T>   //this is for class templatwe
template<class U>   //this is for function template
NumericArray<U> NumericArray<T>::operator * (const U& factor) const
{         //^^^ CHANGED
    NumericArray<U> newArray(Size());  //CHANGED HERE TOO!
    for (int i = 0; i < Size(); i++)
        newArray[i] = factor * GetE(i);
    return newArray;
}

等等!现在这正确吗?如果TdoubleUint 怎么办?上面的问题和上一个完全一样!

所以这是第三次尝试:

template<class T>   //this is for class templatwe
template<class U>   //this is for function template
NumericArray<decltype(std::declval<T>() * std::declval<U>())> 
     NumericArray<T>::operator * (const U& factor) const
{
    typedef decltype(std::declval<T>() * std::declval<U>()) R; //define R
    NumericArray<R> newArray(Size());  //CHANGED HERE!
    for (int i = 0; i < Size(); i++)
        newArray[i] = factor * GetE(i);
    return newArray;
}

所以返回类型是:

NumericArray<R>

R 在哪里:

decltype(std::declval<T>() * std::declval<U>());

这取决于TU 的产品类型。现在是正确的,至少好多了。

希望对您有所帮助。

【讨论】:

  • +1(即使解决了这个问题,我也不对GetE(i) 的返回值抱太大希望)。
  • @WhozCraig:编辑了很多额外的东西。希望这是有道理的。
  • Nawaz,我很感激,但我希望找到一个解决方案,不需要我重新声明和重新定义我的 NumericArray 模板类中的所有构造函数、函数和运算符来合并
  • Nawaz,我很感激,但我希望找到一个解决方案,不需要我在我的 NumericArray 模板类中重新声明和重新定义所有构造函数、函数和运算符来合并额外的类型“U”和“R”。好像一个都没有啊,C++ 的快乐刚性!
  • @user2736224:没有重新定义。只是微小的变化。或者您还想如何解决这些问题?什么都不做?
【解决方案2】:

您的模板代码要求参数和 NumericArray 元素具有相同的时间,这就是 C++ 在乘法之前将 arg 截断为 2 的原因。

要解决这个问题,您应该编写类似的代码

template <class U> template<class T>
NumericArray<T> NumericArray<T>::operator * (const U& factor) const
{
  /***/
}

【讨论】:

  • 为什么不呢?请解释
  • 你的建议完全一样!
  • NOOOOOOOOOOOOO。再来看看!
  • 我只是在模板而不是模板模板中打错了,但是使参数成为独立模板参数的想法是相同的。在您之前发布正确的想法,并带有易于修复的错字。更新:感谢您删除不赞成票
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-30
  • 2021-10-27
相关资源
最近更新 更多