2017-04-27 63 views
3

我想了解爲什麼以下編譯/運行儘管在運行時解析模板類型。是否因爲單獨調用來調用f就足以告訴編譯器創建void f<double>(double)void f<std::string>(std::string)在運行時功能模板類型扣除

test.hpp

#include <type_traits> 
#include <string> 
#include <iostream> 

template <typename T> 
void f(T x) { 
    if(std::is_same<T, std::string>::value) 
     std::cout << "String: " << x; 
} 

TEST.CPP

#include <iostream> 
#include "test.hpp" 

int main(int, char** argv) { 
    double x(std::stod(argv[1])); 

    if(x < 42) f(x); 
    else f(std::to_string(x)); 

    return 0; 
} 

$ (clan)g++ -std=c++14 test.cpp 
$ ./a.exe 41 

$ ./a.exe 43 
String: 43.000000 
+1

爲if和else分支生成代碼。在運行時,根據'x'的值運行相應的分支。 –

回答

8

沒有運行時模板扣除怎麼回事。當你有

if(x < 42) f(x); 

編譯器知道,在編譯的時候,那x是雙所以它戳出來

void f<double>(double) 

然後在

else f(std::to_string(x)); 

編譯器知道的返回類型std::to_stringstd::string所以它蓋了一個

void f<std::string>(std::string) 

使用。兩個函數同時存在,並且只有一個函數在運行時被調用,具體取決於您給程序的輸入。

讓我們看看this example codecomment提供的chris。使用

#include <type_traits> 

template <typename T> 
__attribute__((used)) int f(T x) { 
    if(std::is_same<T, int>::value) 
     return 1; 
    else 
     return 2; 
} 

int main(int argc, char** argv) { 
    if(argc > 1) return f(1); 
    else return f(1.0); 
} 

-O3 -std=c++1z -Wall -Wextra -pedantic編譯生成彙編

main:         # @main 
     xor  eax, eax 
     cmp  edi, 2 
     setl al 
     inc  eax 
     ret 

int f<int>(int):      # @int f<int>(int) 
     mov  eax, 1 
     ret 

int f<double>(double):     # @int f<double>(double) 
     mov  eax, 2 
     ret 

正如你可以看到這兩個模板在裝配中存在的功能,它僅僅是在主要的if是決定哪一個在運行時調用。

+2

爲了說明的目的,你可以看一個沒有''和''膨脹的例子的程序集:https://godbolt.org/g/p2oF34 – chris

+0

@chris不錯的小例子。請注意,如果我將其添加到我的答案中以顯示一些內容? – NathanOliver

+1

完全沒有,SO是社區的努力。 – chris

1
  1. 編譯器讀取main,看到兩個調用f,一旦有一個字符串參數,並曾經與一個int

  2. 產生兩個f秒。調用這兩個函數都嵌入main中。

  3. 您的if語句導致一個或另一個調用。 所以在運行時沒有模板分辨率。這樣的東西不存在。