2017-04-27 61 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语句导致一个或另一个调用。 所以在运行时没有模板分辨率。这样的东西不存在。