为什么类型推导出的T是void func中的const int(T const& t)

时间:2017-02-23 16:22:27

标签: c++ templates type-deduction

我正在阅读模板中的类型推导,这是一个困扰我的问题

template<typename T>
void funt(T const &t);
int x = 10;
func(x);

T将被推断为const intt的类型将为int const & 我理解为什么t必须为int const &的原因,因此传递给函数的x将保持不变,因为函数接受const T&。 但我没有看到T必须也const的原因。在我看来,推断Tint不会破坏这段代码中的任何内容? 就像在另一个例子中一样:

template<typename T>
void funt(T const &t);
int const x = 10;
func(x);

此处T推导为intconst的{​​{1}}被省略

或者我在这里遗漏了什么?

1 个答案:

答案 0 :(得分:2)

类型扣除规则不是很简单。但作为一般经验法则,有3个主要类型扣除案例:

  1. f(/*const volatile*/ T& arg) - 在这种情况下,编译器执行类似于&#34;模式匹配&#34;关于推断类型T的论点。在第二种情况下,它与您的参数类型(即int const)与T const完全匹配,因此T推断为int。如果参数缺少CV限定符,就像在第一个示例中那样,那么编译器在模式匹配中不会考虑它们。所以,当你通过例如int xf(const T& param),然后const在模式匹配期间被丢弃,T被推断为int,因此f被实例化为f(const int&) f(/*const volatile*/ T arg)
  2. cv - 忽略const int& x = otherx; - ness(const / volatile)和参数的references-ness。因此,如果您有x之类的内容并将template<class T> void f(T param)传递给T,那么int会被推断为f(T&& arg)
  3. T - int&被推断为左值引用(如int)或右值(如arg),具体取决于private final Runnable connectToServer = new Thread() { @Override public void run() { try {// Get the server address from a dialog box. String serverAddress = "192.168.0.23"; // Make connection and initialize streams Socket socket = new Socket(serverAddress, 38300); in = new BufferedReader( new InputStreamReader(socket.getInputStream())); out = new PrintWriter(socket.getOutputStream(), true); // Consume the initial welcoming messages from the server for (int i = 0; i < 3; i++) { System.out.println(in.readLine()); } solveCube(); } catch (IOException e) { e.printStackTrace(); } } }; private final Runnable initializeConnection = new Thread() { @Override public void run() { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(generateCubeString()); out.println(generateCubeString()); String response =""; try { response = in.readLine(); if (response == null || response.equals("")) { System.exit(0); } } catch (IOException ex) { } if (response.contains("Error")) { } else { solveCubeAnimate(response); } System.out.println(response); final String finalResponse = response; runOnUiThread(new Runnable() { @Override public void run() { textView.setText(finalResponse); } }); } }; 是否为private static class Capitalizer extends Thread { private Socket socket; private int clientNumber; public Capitalizer(Socket socket, int clientNumber) { this.socket = socket; this.clientNumber = clientNumber; log("New connection with client# " + clientNumber + " at " + socket); } /** * Services this thread's client by first sending the * client a welcome message then repeatedly reading strings * and sending back the capitalized version of the string. */ public void run() { try { // Decorate the streams so we can send characters // and not just bytes. Ensure output is flushed // after every newline. BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); // Send a welcome message to the client. out.println("Hello, you are client #" + clientNumber + "."); out.println("Enter a line with only a period to quit\n"); // Get messages from the client, line by line; return them // capitalized while (true) { String input = in.readLine(); if (input == null || input.equals(".")) { break; } out.println(solveCube(input)); } } catch (IOException e) { log("Error handling client# " + clientNumber + ": " + e); } finally { try { socket.close(); } catch (IOException e) { log("Couldn't close a socket, what's going on?"); } log("Connection with client# " + clientNumber + " closed"); } } /** * Logs a simple message. In this case we just write the * message to the server applications standard output. */ private void log(String message) { System.out.println(message); } } private static class Connecter extends Thread { /** * Services this thread's client by first sending the * client a welcome message then repeatedly reading strings * and sending back the capitalized version of the string. */ public void run() { try { System.out.println("The capitalization server is running."); int clientNumber = 0; ServerSocket listener = new ServerSocket(38300); try { while (true) { new Capitalizer(listener.accept(), clientNumber++).start(); } } finally { listener.close(); } } catch (IOException ex) { Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex); } } } 分别是左值或左值。这个案例有点复杂,我建议您阅读更多有关转发参考和参考折叠规则的信息,以了解正在发生的事情。
  4. Scott Meyers在Effective Modern C++一书的第1章中详细讨论了模板类型推导。该章实际上是免费在线的,请参阅https://www.safaribooksonline.com/library/view/effective-modern-c/9781491908419/ch01.html