Собственно проблема следующая:
Есть тестовый код:
#include <complex>
int _main(int argc, _TCHAR* argv[])
{
std::complex<double> c1(argc, 0), c2(argc, argc);
std::complex<double> c3 = c1 + c2;
return (int)c3.real();
}
После компиляции имеем следующее (листинг из встроенного дизассемблера VisualStudio)
std::complex<double> c1(argc, 0), c2(argc, argc);
003A1009 fild dword ptr [argc]
std::complex<double> c3 = c1 + c2;
003A100C lea eax,[esp]
003A100F push eax
003A1010 lea ecx,[esp+14h]
003A1014 fst qword ptr [esp+14h]
003A1018 push ecx
003A1019 fldz
003A101B lea edx,[esp+28h]
003A101F fstp qword ptr [esp+20h]
003A1023 push edx
003A1024 fst qword ptr [esp+0Ch]
003A1028 fstp qword ptr [esp+14h]
003A102C call dword ptr [__imp_std::operator+<double> (3A2038h)]
return (int)c3.real();
003A1032 fld qword ptr [esp+2Ch]
003A1036 add esp,0Ch
003A1039 call _ftol2_sse (3A1840h)
}
003A103E mov esp,ebp
003A1040 pop ebp
003A1041 ret
Достаточно заменить std::complex<double> на std::complex<int> и сгенерированный код сильно изменится:
std::complex<int> c1(argc, 0), c2(argc, argc);
std::complex<int> c3 = c1 + c2;
00F41006 mov eax,dword ptr [argc]
00F41009 add eax,eax
return (int)c3.real();
}
00F4100B mov esp,ebp
00F4100D pop ebp
00F4100E ret
Собственно именно такой он и должен быть!
Фишка в том, что оператор сложения не подставляется в код, а происходит вызов в CRT библиотеку. Хитрые индусы или кто-то там сделали явные инстанциации шаблона std::complex для типов float, double и long double. Кроме того, они не поленились понавставлять атрибутов __declspec(dllimport) в эти инстанциации.
Самое смешное в том, что MSDN явно говорит про совместное использование ключевых слов inline и dllimport (при этом, если возможно, идет подстановка тела функции, а если невозможно, например берется адрес функции, то вызывается копия из DLL). Идиотизм усугубляется тем, что тестовые DLL и EXE, которые его использует, со своей собственной функцией, работает именно так, как написано в MSDN — то есть правильно!
Но класс для комплексных чисел из стандартной библиотеки отказывается расширятся наотрез! Может кто-то сталкивался с подобным?
Кстати, сия проблема присутствует только если CRT прилинкована как DLL. При статической компоновке все нормально, собственно там макрос стоит который убирает атрибут dllimport в этом случае (а также если мы собираем с ключем /clr:pure). Все пришедшие на ум ключи компилятора были перепробованы. (К слову среда VisualStudio 2008, но насколько я помню и под 2005 будет тоже самое.)
Я все еще надеюсь что я чего-то НИАСИЛИЛ, и у этой проблемы есть решение.
01.02.08 21:13: Перенесено модератором из 'C/C++. Прикладные вопросы' — Кодт