在Visual Studio中编译(基于char)STL(流)容器的错误

问题描述 投票:0回答:1

这与[SO]: C2491: 'std::numpunct<_Elem>::id' : definition of dllimport static data member not allowed [closed]基本上是同一个问题,但考虑到以下事实:

  • 那(在我看来)是一个完全有效的问题(根据[SO]: How to create a Minimal, Complete, and Verifiable example),我真的不知道为什么一些用户感觉到关闭它的冲动
  • 标记为解决方案的答案提供了修复错误的指导(一般情况下),但不适用于当前情况,当然也没有解决,

请不要关闭它或将其标记为重复(至少,不是没有仔细阅读和理解它)。

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

笔记:

  • 一切都是VStudio 2015特定的,但问题是可以使用VStudio 2017,VStudio 2013,VStudio 2010重现(当然,行号不同)。但是,它使用VStudio 2005
  • 我选择从cmdline粘贴编译器命令和输出,而不是使用编译器标志和输出(从VStudio IDE)放置图片,因此它更容易重现(如果有人愿意尝试)
  • 编译器标志是应用程序(.exe)VStudio项目(Win32)的默认值,除了一些不相关的路径相关的(例如.pch文件和其他此类废话),我剥离了
  • 仅在CharType为char(或任何窄字符类型,实际上)或wchar_t时编译。禁用[MS.Docs]: /Zc:wchar_t (wchar_t Is Native Type)会在列表中添加unsigned short(这似乎很自然)
  • 在Lnx(Ubtu 16 x64)/ g ++(gcc 5.4.0)下编译没有问题

[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位字符的基于流的流。

c++ windows visual-studio visual-c++ dllimport
1个回答
0
投票

开始笔记:

处理办法:

  1. 快速(浅)调查 在VStudio IDE上双击,在Output窗口的第二个音符上(尝试编译文件后),然后在相关宏上重复RClicks,并从上下文菜单中选择Go To Definition(F12): xlocnum(#120):(注释是原始文件/行的一部分) __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 这两个选项都不完全令人满意,因此:
  2. 走得更远一点 试图简化事情(main.cpp): #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行) 文件中唯一的区别是#definewchar_tunsigned short)最后的某个地方 编译文件(令人震惊的:))产生了相同的结果:wchar_t编译而unsigned short失败,同样的错误 添加了一些#pragma message语句(是的,它们由预处理器处理,但仍然)在失败的文件中(在每个警告/注释之前),注意到2 #defines之间的一些差异,但到目前为止无法弄清楚为什么1 在浏览生成的文件时,注意到了一个template<> struct char_traits<char32_t>定义,所以我试了一下,它工作了(至少编译了当前的程序)1(并且,正如预期的那样sizeof(char32_t)是4)。然后,找到了[MSDN]: char, wchar_t, char16_t, char32_t 笔记: 虽然这解决了我当前的问题(仍然不知道为什么),但是必须给它一个关于最终目标的镜头 1虽然我查看了该文件,但我没有看到任何模板定义仅针对“特权”类型(例如,我没有看到任何区分wchar_tsigned charchar32_t来自unsigned short的例子),所以我没有知道为什么它适用于某些类型但不适用于其他类型。这是一个开放的话题,每当我得到新的更新时,我都会分享它们

底线:

根据经验发现,在使用基于char的STL容器时,允许使用以下类型:

  • char
  • unsigned char
  • signed char
  • wchar_t
  • char16_t
  • char32_t
  • unsigned short(仅限/Zc:wchar_t-

最后的说明:

  • 我会在答案中加入任何有用的内容(例如评论)

@ EDIT0:

© www.soinside.com 2019 - 2024. All rights reserved.