为什么小于运算符接受不同类型的参数而std :: min不是?

时间:2015-08-11 08:08:46

标签: c++ templates overloading

#include <iostream>

int main(){
    int a = 1;
    long long b = 2;
    std::cout<<(a<b);
    std::cout<<std::min(a, b);
    return 0;
}
> In file included from /usr/include/c++/4.8/bits/char_traits.h:39:0,
>                  from /usr/include/c++/4.8/ios:40,
>                  from /usr/include/c++/4.8/ostream:38,
>                  from /usr/include/c++/4.8/iostream:39,
>                  from sum_to.cpp:1: /usr/include/c++/4.8/bits/stl_algobase.h:239:5: note: template<class
> _Tp, class _Compare> const _Tp& std::min(const _Tp&, const _Tp&, _Compare)
>      min(const _Tp& __a, const _Tp& __b, _Compare __comp)
>      ^ /usr/include/c++/4.8/bits/stl_algobase.h:239:5: note:   template argument deduction/substitution failed: sum_to.cpp:7:29:
> note:   deduced conflicting types for parameter ‘const _Tp’ (‘int’ and
> ‘long long int’)
>      std::cout<<std::min(a, b);

---

感谢chris中的function overloading post评论   模板参数推断不会将转换考虑在内。一   模板参数不能匹配两种类型

所以std::min失败。

为什么<会起作用?

5 个答案:

答案 0 :(得分:7)

因为内置<适用Numeric promotions,模板参数扣除不适用。

答案 1 :(得分:3)

正如其他答案中所解释的那样,原因是std::min要求在执行演绎时参数的类型相同,而<则表示通常的算术转换(§5.9/ 2) ),这将确保类型转换为“共同点”。请注意§13.6/ 12如何将内置运算符列为候选运算符:

  

对于每对提升的算术类型LR,都存在   表格的候选运算符函数

// […]
LR operator<(L , R );
// […]
     

其中LR是通常算术转换的结果   类型LR

实际上,std::min应该能够处理不同的类型。以下是一种更现代的方法:

template <typename T>
constexpr decltype(auto) min(T&& t) {return std::forward<T>(t);}

template <typename T, typename U, typename... Args>
constexpr auto min(T&& t, U&&u, Args&&... args) {
    std::common_type_t<T, U> const& _t(std::forward<T>(t)), _u(std::forward<U>(u));
    return min(_t<_u? _t : _u, std::forward<Args>(args)...);
}

Demo

答案 2 :(得分:2)

这是因为std::min是模板函数。

mvn install

所以它需要具有相同类型的参数,但如果您使用[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.18.1:test (default-test) on project MavenTest: Execution default-test of goal org.apache.maven.plugins:maven-surefire-plugin:2.18.1:test failed: There was an error in the forked process [ERROR] java.lang.UnsupportedClassVersionError: org/testng/annotations/Test : Unsupported major.minor version 52.0 [ERROR] at java.lang.ClassLoader.defineClass1(Native Method) [ERROR] at java.lang.ClassLoader.defineClass(Unknown Source) [ERROR] at java.security.SecureClassLoader.defineClass(Unknown Source) [ERROR] at java.net.URLClassLoader.defineClass(Unknown Source) [ERROR] at java.net.URLClassLoader.access$100(Unknown Source) [ERROR] at java.net.URLClassLoader$1.run(Unknown Source) [ERROR] at java.net.URLClassLoader$1.run(Unknown Source) [ERROR] at java.security.AccessController.doPrivileged(Native Method) [ERROR] at java.net.URLClassLoader.findClass(Unknown Source) [ERROR] at java.lang.ClassLoader.loadClass(Unknown Source) [ERROR] at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) [ERROR] at java.lang.ClassLoader.loadClass(Unknown Source) [ERROR] at org.apache.maven.surefire.util.ReflectionUtils.tryLoadClass(ReflectionUtils.java:229) [ERROR] at org.apache.maven.surefire.testng.TestNGExecutor.<clinit>(TestNGExecutor.java:59) [ERROR] at org.apache.maven.surefire.testng.TestNGXmlTestSuite.execute(TestNGXmlTestSuite.java:84) [ERROR] at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:90) [ERROR] at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:203) [ERROR] at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:155) [ERROR] at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103) ,那么template <class T> const T& min (const T& a, const T& b) { return !(b<a)?a:b; // or: return !comp(b,a)?a:b; for version (2) } 可以隐式转换为(a<b)

答案 3 :(得分:-1)

原始类型不会使运算符重载,因此应用通常的算术转换并将int转换为long long,并且“&lt;”有一个有效的意义。

你甚至无法为基本类型重载运算符: https://isocpp.org/wiki/faq/intrinsic-types#intrinsics-and-operator-overloading

示例表明你的int被提升为long long

// common_type example
#include <iostream>
#include <type_traits>

int main() {

  typedef std::common_type<int, long long>::type A;           // i
  std::cout << "A: " << std::is_same<long long,A>::value << std::endl;

  return 0;
}

文档 http://en.cppreference.com/w/cpp/language/operator_arithmetic

  

对于二元运算符(除了shift),如果是提升的操作数   有不同的类型,另外一组隐式转换是   应用,称为通常的算术转换,目标是   生成公共类型(也可以通过std :: common_type类型访问)   性状)

答案 4 :(得分:-1)

long time = 0; Stopwatch watch = new Stopwatch(); watch.Start(); Image img = Image.FromFile("test.png"); byte[] data; MemoryStream ms = new MemoryStream(); img.Save(ms, ImageFormat.Bmp); data = ms.ToArray(); watch.Stop(); time = watch.ElapsedTicks; Console.WriteLine(time); FileStream file = new FileStream("test.txt", FileMode.Create, FileAccess.ReadWrite); StreamWriter writer = new StreamWriter(file); foreach (byte b in data) { writer.WriteLine(b); } writer.Close(); file.Close(); Console.ReadKey();` 运算符是二进制的,因此编译器可以将参数转换为相同的类型并进行比较。

否则<函数应该返回一些东西。编译器如何猜测他应该返回哪种类型?