这与[SO]: C2491: 'std::numpunct<_Elem>::id' : definition of dllimport static data member not allowed [closed]基本上是同一个问题,但考虑到以下事实:
请不要关闭它或将其标记为重复(至少,不是没有仔细阅读和理解它)。
main.cpp中:
#include <sstream>
//#define THROW_C2491
#if defined(THROW_C2491)
typedef int CharType;
#else
typedef char CharType;
#endif
int main() {
std::basic_stringstream<CharType> stream;
CharType c = 0x41;
stream << c;
return 0;
}
代码稍作修改(简化),如果定义了THROW_C2491
则无法编译:
xlocnum(294): error C2491: 'std::numpunct<_Elem>::id': definition of dllimport static data member not allowed
输出:
E:\Work\Dev\StackOverflow\q048716223>"c:\Install\x86\Microsoft\Visual Studio Community\2015\vc\vcvarsall.bat" amd64 E:\Work\Dev\StackOverflow\q048716223> E:\Work\Dev\StackOverflow\q048716223>"c:\Install\x86\Microsoft\Visual Studio Community\2015\vc\bin\amd64\cl.exe" /GS /W3 /Zc:wchar_t /ZI /Gm /Od /Zc:inline /fp:precise /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /EHsc /nologo -c "src\main.cpp" main.cpp E:\Work\Dev\StackOverflow\q048716223>echo %errorlevel% 0 E:\Work\Dev\StackOverflow\q048716223> E:\Work\Dev\StackOverflow\q048716223>"c:\Install\x86\Microsoft\Visual Studio Community\2015\vc\bin\amd64\cl.exe" /GS /W3 /Zc:wchar_t /ZI /Gm /Od /Zc:inline /fp:precise /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /EHsc /nologo -c "src\main.cpp" /D "THROW_C2491" main.cpp c:\install\x86\microsoft\visual studio community\2015\vc\include\xlocnum(294): warning C4273: 'id': inconsistent dll linkage c:\install\x86\microsoft\visual studio community\2015\vc\include\xlocnum(120): note: see previous definition of 'public: static std::locale::id std::numpunct<int>::id' c:\install\x86\microsoft\visual studio community\2015\vc\include\xlocnum(120): note: while compiling class template static data member 'std::locale::id std::numpunct<_Elem>::id' with [ _Elem=CharType ] c:\install\x86\microsoft\visual studio community\2015\vc\include\xlocnum(1261): note: see reference to function template instantiation 'const _Facet &std::use_facet<std::numpunct<_Elem>>(const std::locale &)' being compiled with [ _Facet=std::numpunct<CharType>, _Elem=CharType ] c:\install\x86\microsoft\visual studio community\2015\vc\include\xlocnum(1255): note: while compiling class template member function 'std::ostreambuf_iterator<_Elem,_Traits> std::num_put<_Elem,std::ostreambuf_iterator<_Elem,_Traits>>::do_put(_OutIt,std::ios_base &,_Elem,bool) const' with [ _Elem=CharType, _Traits=std::char_traits<CharType>, _OutIt=std::ostreambuf_iterator<CharType,std::char_traits<CharType>> ] c:\install\x86\microsoft\visual studio community\2015\vc\include\ostream(305): note: see reference to class template instantiation 'std::num_put<_Elem,std::ostreambuf_iterator<_Elem,_Traits>>' being compiled with [ _Elem=CharType, _Traits=std::char_traits<CharType> ] c:\install\x86\microsoft\visual studio community\2015\vc\include\ostream(291): note: while compiling class template member function 'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(int)' with [ _Elem=CharType, _Traits=std::char_traits<CharType> ] e:\work\dev\stackoverflow\q048716223\src\main.cpp(16): note: see reference to function template instantiation 'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(int)' being compiled with [ _Elem=CharType, _Traits=std::char_traits<CharType> ] c:\install\x86\microsoft\visual studio community\2015\vc\include\istream(939): note: see reference to class template instantiation 'std::basic_ostream<_Elem,_Traits>' being compiled with [ _Elem=CharType, _Traits=std::char_traits<CharType> ] c:\install\x86\microsoft\visual studio community\2015\vc\include\sstream(574): note: see reference to class template instantiation 'std::basic_iostream<_Elem,_Traits>' being compiled with [ _Elem=CharType, _Traits=std::char_traits<CharType> ] e:\work\dev\stackoverflow\q048716223\src\main.cpp(14): note: see reference to class template instantiation 'std::basic_stringstream<CharType,std::char_traits<_Elem>,std::allocator<_Elem>>' being compiled with [ _Elem=CharType ] c:\install\x86\microsoft\visual studio community\2015\vc\include\xlocnum(294): error C2491: 'std::numpunct<_Elem>::id': definition of dllimport static data member not allowed with [ _Elem=CharType ] E:\Work\Dev\StackOverflow\q048716223>echo %errorlevel% 2
笔记:
[MS.Docs]: Compiler Error C2491非常简单,我熟悉它,有一些答案(例如[SO]: Linker error when calling a C function from C++ code in different VS2010 project (@CristiFati's answer),[SO]: Excel VBA, Can't Find DLL Entry Point from a DLL file (@CristiFati's answer))支持我。
考虑到上面的注释,我知道这与处理字符的Win的方式(限制?)有关,但我没有看到代码和错误之间的任何(立即)连接。没有关于[MS.Docs]: basic_stringstream Class上的这种行为。我(浅)浏览了所涉及的标准包括标题,但到目前为止我没有到达底部。我错过了smth非常明显吗?
其他引用(相同或类似的错误,但没有包含有效的修复):
值得一提的是,最终目标是构建一些第三方软件,实例化一些基于32位字符的基于流的流。
开始笔记:
处理办法:
__PURE_APPDOMAIN_GLOBAL _CRTIMP2_PURE static locale::id id; // unique facet id
yvals.h:(#494):
#define _CRTIMP2_PURE _CRTIMP2
crtdefs.h(#29 +):
#ifndef _CRTIMP2
#if defined CRTDLL2 && defined _CRTBLD
#define _CRTIMP2 __declspec(dllexport)
#else
#if defined _DLL && !defined _STATIC_CPPLIB
#define _CRTIMP2 __declspec(dllimport) // @TODO - cfati: line #34: Here is the definition
#else
#define _CRTIMP2
#endif
#endif
#endif
如图所示,__declspec(dllimport)
在第34行定义。在_DLL
宏上重复该过程,没有产生任何结果。在[MSDN]: Predefined Macros上找到:
_DLL在设置/MD或/MDd(多线程DLL)编译器选项时定义为1。否则,未定义。
我想到了两种可能的方法(两者都导致了成功的构建):
使用CRT Runtime的静态版本([MSDN]: /MD, /MT, /LD (Use Run-Time Library))。我不认为这是一个可行的选择,特别是当项目由.dll组成时(并且确实如此):可能发生坏事(例如[SO]: Errors when linking to protobuf 3 on MSVC 2013,甚至更糟糕的事情可能在运行时发生)
手动#undef _DLL
(在main.cpp,在任何#include
之前)。这是一个蹩脚的解决方法(获得者)。它构建得很好,但是篡改这些东西可能(并且很可能会)在运行时触发Undefined Behavior
这两个选项都不完全令人满意,因此:#include <sstream>
//typedef unsigned short CharType; // wchar_t unsigned short
#define CharType unsigned short
int main() {
std::basic_stringstream<CharType> stream;
CharType c = 0x41;
stream << c;
return 0;
}
笔记:
用typedef
替换#define
(去除新的类型定义复杂性)
切换到unsigned short
,这是wchar_t
的定义(/Zc:wchar_t-
),以避免任何可能的类型大小/对齐差异
使用[MSDN]: /E (Preprocess to stdout)和[MSDN]: /EP (Preprocess to stdout Without #line Directives)“编译”上面的代码(以便警告/错误仅引用当前文件中的行号):
生成的预处理文件(使用每个标志来自bove):~1MB +(~56.5k行)
文件中唯一的区别是#define
(wchar_t
与unsigned short
)最后的某个地方
编译文件(令人震惊的:))产生了相同的结果:wchar_t
编译而unsigned short
失败,同样的错误
添加了一些#pragma message
语句(是的,它们由预处理器处理,但仍然)在失败的文件中(在每个警告/注释之前),注意到2 #define
s之间的一些差异,但到目前为止无法弄清楚为什么1
在浏览生成的文件时,注意到了一个template<> struct char_traits<char32_t>
定义,所以我试了一下,它工作了(至少编译了当前的程序)1(并且,正如预期的那样sizeof(char32_t)
是4)。然后,找到了[MSDN]: char, wchar_t, char16_t, char32_t
笔记:
虽然这解决了我当前的问题(仍然不知道为什么),但是必须给它一个关于最终目标的镜头
1虽然我查看了该文件,但我没有看到任何模板定义仅针对“特权”类型(例如,我没有看到任何区分wchar_t
,signed char
或char32_t
来自unsigned short
的例子),所以我没有知道为什么它适用于某些类型但不适用于其他类型。这是一个开放的话题,每当我得到新的更新时,我都会分享它们底线:
根据经验发现,在使用基于char的STL容器时,允许使用以下类型:
char
unsigned char
signed char
wchar_t
char16_t
char32_t
unsigned short
(仅限/Zc:wchar_t-
)最后的说明:
@ EDIT0:
unsigned char
和signed char
静态和动态C ++ RTLib之间的区别
我将接受这个作为答案。