У меня есть некоторый шаблонный код, который реализует довольно сложные вычисления, но он мне нужен только для чисел с плавающей запятой и двойных чисел Цель состоит в том, чтобы создание шаблона выполнялось только один раз в одном модуле компиляции и не повторялось для каждого файла.
Я пытался следовать идеям следующих постов Stackoverflow:
и похожи на дубликаты вопросов. Я придумал следующий тест, чтобы проиллюстрировать проблему:
хиджры
#pragma once
#include <cmath>
template<typename T>
struct A
{
static T foo(T a, T b)
{
//do some heavy computations
T v1 = pow(a, b);
return pow(v1, b);
}
};
//explicit template instantiations, the declaration
extern template struct A<float>;
extern template struct A<double>;
a.cpp
#include "A.h"
//explicit template instantiations, the definition
template struct A<float>;
template struct A<double>;
main.cpp
#include "A.h"
int main()
{
//use A
float result = A<float>::foo(0, 0);
return (int)result; //return it so that it doesn't get optimized away
}
Когда я сейчас смотрю на сгенерированный файл .obj (dumpbin / DISASM), я получаю следующий вывод:
A.obj
Dump of file A.obj
File Type: COFF OBJECT
?foo@?$A@M@@SAMMM@Z (public: static float __cdecl A<float>::foo(float,float)):
0000000000000000: F3 0F 11 4C 24 10 movss dword ptr [rsp+10h],xmm1
0000000000000006: F3 0F 11 44 24 08 movss dword ptr [rsp+8],xmm0
000000000000000C: 55 push rbp
000000000000000D: 57 push rdi
000000000000000E: 48 81 EC 18 01 00 sub rsp,118h
00
0000000000000015: 48 8D 6C 24 30 lea rbp,[rsp+30h]
000000000000001A: 48 8B FC mov rdi,rsp
000000000000001D: B9 46 00 00 00 mov ecx,46h
0000000000000022: B8 CC CC CC CC mov eax,0CCCCCCCCh
0000000000000027: F3 AB rep stos dword ptr [rdi]
0000000000000029: F3 0F 10 8D 08 01 movss xmm1,dword ptr [rbp+108h]
00 00
0000000000000031: F3 0F 10 85 00 01 movss xmm0,dword ptr [rbp+100h]
00 00
0000000000000039: E8 00 00 00 00 call ?pow@@YAMMM@Z
000000000000003E: F3 0F 11 45 04 movss dword ptr [rbp+4],xmm0
0000000000000043: F3 0F 10 8D 08 01 movss xmm1,dword ptr [rbp+108h]
00 00
000000000000004B: F3 0F 10 45 04 movss xmm0,dword ptr [rbp+4]
0000000000000050: E8 00 00 00 00 call ?pow@@YAMMM@Z
0000000000000055: 48 8D A5 E8 00 00 lea rsp,[rbp+0E8h]
00
000000000000005C: 5F pop rdi
000000000000005D: 5D pop rbp
000000000000005E: C3 ret
?foo@?$A@N@@SANNN@Z (public: static double __cdecl A<double>::foo(double,double)):
0000000000000000: F2 0F 11 4C 24 10 movsd mmword ptr [rsp+10h],xmm1
0000000000000006: F2 0F 11 44 24 08 movsd mmword ptr [rsp+8],xmm0
000000000000000C: 55 push rbp
000000000000000D: 57 push rdi
000000000000000E: 48 81 EC 18 01 00 sub rsp,118h
00
0000000000000015: 48 8D 6C 24 30 lea rbp,[rsp+30h]
000000000000001A: 48 8B FC mov rdi,rsp
000000000000001D: B9 46 00 00 00 mov ecx,46h
0000000000000022: B8 CC CC CC CC mov eax,0CCCCCCCCh
0000000000000027: F3 AB rep stos dword ptr [rdi]
0000000000000029: F2 0F 10 8D 08 01 movsd xmm1,mmword ptr [rbp+108h]
00 00
0000000000000031: F2 0F 10 85 00 01 movsd xmm0,mmword ptr [rbp+100h]
00 00
0000000000000039: E8 00 00 00 00 call pow
000000000000003E: F2 0F 11 45 08 movsd mmword ptr [rbp+8],xmm0
0000000000000043: F2 0F 10 8D 08 01 movsd xmm1,mmword ptr [rbp+108h]
00 00
000000000000004B: F2 0F 10 45 08 movsd xmm0,mmword ptr [rbp+8]
0000000000000050: E8 00 00 00 00 call pow
0000000000000055: 48 8D A5 E8 00 00 lea rsp,[rbp+0E8h]
00
000000000000005C: 5F pop rdi
000000000000005D: 5D pop rbp
000000000000005E: C3 ret
....
Main.obj
Dump of file Main.obj
File Type: COFF OBJECT
?foo@?$A@M@@SAMMM@Z (public: static float __cdecl A<float>::foo(float,float)):
0000000000000000: F3 0F 11 4C 24 10 movss dword ptr [rsp+10h],xmm1
0000000000000006: F3 0F 11 44 24 08 movss dword ptr [rsp+8],xmm0
000000000000000C: 55 push rbp
000000000000000D: 57 push rdi
000000000000000E: 48 81 EC 18 01 00 sub rsp,118h
00
0000000000000015: 48 8D 6C 24 30 lea rbp,[rsp+30h]
000000000000001A: 48 8B FC mov rdi,rsp
000000000000001D: B9 46 00 00 00 mov ecx,46h
0000000000000022: B8 CC CC CC CC mov eax,0CCCCCCCCh
0000000000000027: F3 AB rep stos dword ptr [rdi]
0000000000000029: F3 0F 10 8D 08 01 movss xmm1,dword ptr [rbp+108h]
00 00
0000000000000031: F3 0F 10 85 00 01 movss xmm0,dword ptr [rbp+100h]
00 00
0000000000000039: E8 00 00 00 00 call ?pow@@YAMMM@Z
000000000000003E: F3 0F 11 45 04 movss dword ptr [rbp+4],xmm0
0000000000000043: F3 0F 10 8D 08 01 movss xmm1,dword ptr [rbp+108h]
00 00
000000000000004B: F3 0F 10 45 04 movss xmm0,dword ptr [rbp+4]
0000000000000050: E8 00 00 00 00 call ?pow@@YAMMM@Z
0000000000000055: 48 8D A5 E8 00 00 lea rsp,[rbp+0E8h]
00
000000000000005C: 5F pop rdi
000000000000005D: 5D pop rbp
000000000000005E: C3 ret
....
A::foo
создается в A.obj, как и ожидалось. Но код снова помещается в Main.obj, полностью игнорируя ключевое слово extern
.
Как я могу сказать компилятору (Visual Studio 2017, режим выпуска) НЕ использовать метод inline, а использовать версию из A.obj?