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

时间:2019-06-23 15:32:39

标签: c++ compiler-errors max

std::max()函数中使用两种不同的数字变量类型时,c ++编译器是否有错误原因? (例如intlong)。

我的意思是这样的:“有时候,当将std::max()函数用于两种不同的数字变量类型时,我们会遇到此问题,因此编译器会给出错误以防止出现此问题。”

3 个答案:

答案 0 :(得分:5)

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

如果通过显式提供模板参数来解决推导模糊性,则可以将不同类型用作std::max参数

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

@bolov的答案描述了std::max坚持为其参数使用通用类型(而不是使用两个独立类型)的原因:该函数实际上要返回一个 reference 达到最大值。

答案 1 :(得分:3)

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

并且由于它返回对参数的引用,因此所有参数必须具有相同的类型。

答案 2 :(得分:2)

该问题的直接答案是因为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是哪种类型?

即使我们已将其传递给intunsigned,结果的类型(至少可能)也不是intunsigned