为什么 c++ 编译器在对两种不同类型的数值变量使用"std::max()"函数时会出现错误

Why c++ compiler gives error when using `std::max()` function for two different type of numeric variable

本文关键字:quot max std 函数 错误 两种 编译器 c++ 同类型 变量 为什么      更新时间:2023-10-16

在函数中使用两种不同的数值变量类型时,c++ 编译器有什么原因std::max()给出错误吗?(例如intlong)。

我的意思是:">有时我们在对两种不同的数值变量类型使用函数时会遇到这个问题std::max()所以编译器会给出错误以防止这个问题"。

编译器产生错误,因为它无法对std::max的模板参数执行类型推断。这就是std::max模板的声明方式:两个参数使用相同的类型(模板参数)。如果参数具有不同的类型,则推论变得模棱两可。

如果您通过显式提供模板参数来解决演绎歧义,您将能够使用不同的类型作为std::max参数

std::max(1, 2.0); // Error
std::max<double>(1, 2.0); // OK
std::max

坚持为其参数使用公共类型(而不是使用两个独立类型)的原因在@bolov的答案中进行了描述:该函数实际上希望返回对最大值的引用

std::max返回对具有最大值的参数的引用。采用这种方式的主要原因是因为它是一个泛型函数,因此它可以与复制成本高昂的类型一起使用。此外,您可能实际上只需要对对象的引用,而不是它的副本。

由于它返回对参数的引用,因此所有参数必须属于同一类型。

这个问题的直接答案是,这是因为std::minstd::max只接受一个定义两个参数类型的模板参数。如果/当您尝试传递不同类型的参数时,编译器无法决定将这两种类型中的哪一种用于模板参数,因此代码不明确。根据C++98中的最初定义,std::minstd::max具有以下签名(C++03,§[lib.alg.min.max]):

template<class T> const T& min(const T& a, const T& b);
template<class T, class Compare>
const T& min(const T& a, const T& b, Compare comp);
template<class T> const T& max(const T& a, const T& b);
template<class T, class Compare>
const T& max(const T& a, const T& b, Compare comp);

因此,这里的基本思想是函数通过引用接收两个对象,并返回对其中一个对象的引用。如果它收到两种不同类型的对象,它将无法返回对输入对象的引用,因为其中一个对象必然与它返回的类型不同(所以@bolov关于这部分是正确的,但我认为这不是真正的故事)。

使用现代编译器/标准库,如果您不处理值而不是引用,则可以轻松地按照以下一般顺序编写代码:

template <class T, class U>
std::common_type<T, U> min(T const &a, U const &b) { 
return b < a ? b : a;
}
template <class T, class U>
std::common_type<T, U> max(T const &a, U const &b) { 
return a < b ? b : a;
}

这使得处理传递intlong(或其他类型对,只要std::common_type可以为它们推断出一些通用类型,并且为这两种类型的对象定义a<b的情况变得非常容易。

但是,在 1998 年,即使std::common_type可用,所以很容易做到,这个解决方案可能不会被接受(正如我们将看到的,它仍然存在一些问题,它是否是一个好主意)——当时,许多人仍然认为大量的继承,所以(或多或少)被认为是理所当然的,你会经常在两个参数都确实派生的情况下使用它。键入,此一般顺序上的内容:

class Base { 
// ...
virtual bool operator<(Base const &other);
};
class Derived1 : public Base {
// ...
};
class Derived2 : public Base {
// ...
};
Derived1 d1;
Derived2 d2;
Base &b = std::max(d1, d2);

在这种情况下,上面返回值而不是返回引用的版本会导致严重的问题。common_type<Derived1, Derived2>将是Base的,所以我们最终会切片参数以创建一个类型为Base的对象,并返回它。这很少会提供理想的行为(在某些情况下,例如,如果Base是一个抽象基类,它甚至不会编译)。

还有一点可能值得注意:即使在看似简单的情况下应用,std::common_type也可以产生您可能意想不到的结果。例如,让我们考虑调用上面定义的模板,如下所示:

auto x = min(-1, 1u);

这给我们留下了一个明显的问题:x会是什么类型?

即使我们已经传递了一个int和一个unsigned,结果的类型(至少可能)既不是int也不是unsigned(例如,很可能是long long)!