我正在阅读模板中的类型推导,这是一个困扰我的问题
template<typename T>
void funt(T const &t);
int x = 10;
func(x);
T
将被推断为const int
,t
的类型将为int const &
我理解为什么t
必须为int const &
的原因,因此传递给函数的x
将保持不变,因为函数接受const T&
。
但我没有看到T
必须也const
的原因。在我看来,推断T
为int
不会破坏这段代码中的任何内容?
就像在另一个例子中一样:
template<typename T>
void funt(T const &t);
int const x = 10;
func(x);
此处T
推导为int
,const
的{{1}}被省略
或者我在这里遗漏了什么?
答案 0 :(得分:2)
类型扣除规则不是很简单。但作为一般经验法则,有3个主要类型扣除案例:
f(/*const volatile*/ T& arg)
- 在这种情况下,编译器执行类似于&#34;模式匹配&#34;关于推断类型T
的论点。在第二种情况下,它与您的参数类型(即int const
)与T const
完全匹配,因此T
推断为int
。如果参数缺少CV限定符,就像在第一个示例中那样,那么编译器在模式匹配中不会考虑它们。所以,当你通过例如int x
到f(const T& param)
,然后const
在模式匹配期间被丢弃,T
被推断为int
,因此f
被实例化为f(const int&)
f(/*const volatile*/ T arg)
。cv
- 忽略const int& x = otherx;
- ness(const / volatile)和参数的references-ness。因此,如果您有x
之类的内容并将template<class T> void f(T param)
传递给T
,那么int
会被推断为f(T&& arg)
。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);
}
}
}
分别是左值或左值。这个案例有点复杂,我建议您阅读更多有关转发参考和参考折叠规则的信息,以了解正在发生的事情。 Scott Meyers在Effective Modern C++一书的第1章中详细讨论了模板类型推导。该章实际上是免费在线的,请参阅https://www.safaribooksonline.com/library/view/effective-modern-c/9781491908419/ch01.html。