当操作数类型为short时,编译模板标量向量加法运算符失败

时间:2022-08-26 18:52:13

I am using auto, decltype and declval in a simple vector class in order to perform basic vector operations e.g. addition of a scalar and a vector. However, I have trouble making it work when trying to add a scalar of type short and a vector of type short.

我在一个简单的向量类中使用auto,decltype和declval,以便执行基本的向量操作,例如添加标量和矢量。但是,在尝试添加short类型和short类型的向量时,我无法使其工作。

// Vector.h
#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>
using namespace std;

template<typename T> class Vector;
template<typename T> std::ostream& operator<< ( std::ostream& s, const Vector<T>& other );

template<typename T>
class Vector {
  std::vector<T> base;

  // vector + scalar
  template<typename T1, typename T2>
  friend auto operator+(const Vector<T1> & lhs, const T2 & scalar) -> Vector<decltype(std::declval<T1>() + std::declval<T2>())>;         

  friend std::ostream& operator<< <T> ( std::ostream& s, const Vector<T>& other );

public:
  Vector();
  Vector( const Vector<T>& other );
  Vector<T>& operator= ( const Vector<T> &other );
  auto& operator[] ( int i );
  void insert( const T element );
};

template<typename T>
Vector<T>::Vector() {
}

template<typename T>
Vector<T>::Vector( const Vector<T>& other ) {
  base = other.base;
}

template<typename T>
Vector<T>& Vector<T>::operator= ( const Vector<T> &other ) {
  base = other.base;
}

template<typename T>
auto& Vector<T>::operator[] ( int i ) {
  assert( i >= 0 && i < base.size() );
  return base[i];
}

template<typename T>
void Vector<T>::insert( const T element ) {
  base.push_back( element );
}

// vector + scalar
template<typename T1, typename T2>
auto operator+(const Vector<T1> & lhs, const T2 & scalar)
  -> Vector<decltype(std::declval<T1>() + std::declval<T2>())>
{
  typedef decltype(std::declval<T1>() + std::declval<T2>()) T3;
  Vector<T3> result;
  result.base.reserve(lhs.base.size());
  std::transform(lhs.base.begin(), lhs.base.end(), std::back_inserter(result.base),
                 [&scalar](const T1 & element) { return element + scalar; });
  return result;
}

Test program:

// vector_test.cpp

void test_vector_int_scalar_int_addition() {
  Vector<int> v;
  v.insert( 1 );
  v.insert( 2 );
  v.insert( 3 );
  int s = 2;
  Vector<int> res = v + s;
  }

void test_vector_short_scalar_short_addition() {
   Vector<short> v;
   v.insert( 1 );
   v.insert( 2 );
   v.insert( 3 );
   short s = 2;
   Vector<short> res = v + s;
}

int main() {
   test_vector_int_scalar_int_addition(); // Compiles and works
   test_vector_short_scalar_short_addition(); // Does NOT compile
}

Compiling the above fails for the case using short "test_vector_short_scalar_short_addition()", but works fine when using int "test_vector_int_scalar_int_addition()". I get the following error:

对于使用简短的“test_vector_short_scalar_short_addition()”的情况,编译上述内容失败,但在使用int“test_vector_int_scalar_int_addition()”时工作正常。我收到以下错误:

 error: no viable conversion from 'Vector&ltdecltype(std::declval&ltshort>() + std::declval&ltshort>())>' to 'Vector&ltshort>'

What puzzles me is that is works fine for other types e.g. double, float, long etc. but appears to fail only when using short.

让我感到困惑的是,对其他类型的工作正常double,float,long等,但只有在使用short时才会出现故障。

Compiler info:

clang++ --version
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)

2 个解决方案

#1


5  

The operands of the built-in addition operator undergo the usual arithmetic conversions, which include integral promotions, which means that most integral types that have an integer conversion rank less than that of int are converted to int.

内置加法运算符的操作数经历了通常的算术转换,其中包括整数提升,这意味着整数转换排名小于int的整数类型转换为int。

The above means that your Vector<decltype(std::declval<short>() + std::declval<short>())> is actually Vector<int>, and the compiler complains that it can't convert it to Vector<short>.

上面的意思是你的Vector ()+ std :: declval ())>实际上是Vector ,并且编译器抱怨它无法将其转换为Vector <短> 。 (std>

This can be verified using the following code:

这可以使用以下代码进行验证:

#include <iostream>
#include <type_traits>

int main()
{
    std::cout << std::is_same<decltype(std::declval<short>() + std::declval<short>()), int>::value << '\n';
}

which prints 1.

打印1。


As an alternative for determining the type of the result, you could consider std::common_type. This will give you a short if both operands are short, but will still apply the usual arithmetic conversions if the types are different - for example, unsigned short and short will typically yield int (if sizeof(short) < sizeof(int)).

作为确定结果类型的替代方法,您可以考虑使用std :: common_type。如果两个操作数都很短,这将给你一个短路,但如果类型不同,仍会应用通常的算术转换 - 例如,unsigned short和short通常会产生int(如果sizeof(short) (int))。

#2


1  

The above behavior can be reproduced by this simple example:

通过这个简单的例子可以重现上述行为:

short a = 1, b = 1;
auto res = a + b; // decltype(res) == int

As part of the usual arithmetic conversions, both operands (shorts) undergo integral promotion and are converted to int. This is not the case with float or double as they are floating-point types. Since the rank of short is less than that of int, the result of the operation is converted to int, if it can be.

作为通常的算术转换的一部分,两个操作数(短路)都经过整体提升并转换为int。 float或double不是这种情况,因为它们是浮点类型。由于short的等级小于int的等级,因此操作的结果将转换为int,如果可以的话。

http://en.cppreference.com/w/c/language/conversion#Usual_arithmetic_conversions

#1


5  

The operands of the built-in addition operator undergo the usual arithmetic conversions, which include integral promotions, which means that most integral types that have an integer conversion rank less than that of int are converted to int.

内置加法运算符的操作数经历了通常的算术转换,其中包括整数提升,这意味着整数转换排名小于int的整数类型转换为int。

The above means that your Vector<decltype(std::declval<short>() + std::declval<short>())> is actually Vector<int>, and the compiler complains that it can't convert it to Vector<short>.

上面的意思是你的Vector ()+ std :: declval ())>实际上是Vector ,并且编译器抱怨它无法将其转换为Vector <短> 。 (std>

This can be verified using the following code:

这可以使用以下代码进行验证:

#include <iostream>
#include <type_traits>

int main()
{
    std::cout << std::is_same<decltype(std::declval<short>() + std::declval<short>()), int>::value << '\n';
}

which prints 1.

打印1。


As an alternative for determining the type of the result, you could consider std::common_type. This will give you a short if both operands are short, but will still apply the usual arithmetic conversions if the types are different - for example, unsigned short and short will typically yield int (if sizeof(short) < sizeof(int)).

作为确定结果类型的替代方法,您可以考虑使用std :: common_type。如果两个操作数都很短,这将给你一个短路,但如果类型不同,仍会应用通常的算术转换 - 例如,unsigned short和short通常会产生int(如果sizeof(short) (int))。

#2


1  

The above behavior can be reproduced by this simple example:

通过这个简单的例子可以重现上述行为:

short a = 1, b = 1;
auto res = a + b; // decltype(res) == int

As part of the usual arithmetic conversions, both operands (shorts) undergo integral promotion and are converted to int. This is not the case with float or double as they are floating-point types. Since the rank of short is less than that of int, the result of the operation is converted to int, if it can be.

作为通常的算术转换的一部分,两个操作数(短路)都经过整体提升并转换为int。 float或double不是这种情况,因为它们是浮点类型。由于short的等级小于int的等级,因此操作的结果将转换为int,如果可以的话。

http://en.cppreference.com/w/c/language/conversion#Usual_arithmetic_conversions