C++ Visual Studio 2013:自定义枚举的链接器错误?

C++ Visual Studio 2013:自定义枚举的链接器错误?,c++,boost,visual-studio-2013,enums,linker,C++,Boost,Visual Studio 2013,Enums,Linker,我使用James McNellis编写的以下代码来简化更具功能性的C++2011枚举的声明: #pragma once #include <stdexcept> #include <boost/preprocessor.hpp> #include <vector> // Internal helper to provide partial specialization for checked_enum_cast template <typename T

我使用James McNellis编写的以下代码来简化更具功能性的C++2011枚举的声明:

#pragma once
#include <stdexcept>
#include <boost/preprocessor.hpp>
#include <vector>

// Internal helper to provide partial specialization for checked_enum_cast
template <typename Target, typename Source>
struct checked_enum_cast_impl;

// Exception thrown by checked_enum_cast on cast failure
struct invalid_enum_cast : std::out_of_range
{
    invalid_enum_cast(const char* s)
        : std::out_of_range(s) { }
};

// Checked cast function
template <typename Target, typename Source>
Target checked_enum_cast(Source s)
{
    return checked_enum_cast_impl<Target, Source>::do_cast(s);
}

// Internal helper to help declare case labels in the checked cast function
#define X_DEFINE_SAFE_CAST_CASE(r, data, elem) case elem:

// How to do this? Question asked on StackOverflow 11/30/14 -- check back again soon.
#define X_ADD_TO_TORET(r, data, elem) ToRet.push_back(elem)

// Defines an enumeration with a checked cast function.
//   name is the name of the enumeration to be defined
//   enumerators is the preprocessing sequence of enumerators to be defined.
#define DENUM(name, enumerators)                           \
enum name                                                              \
{                                                                      \
    BOOST_PP_SEQ_ENUM(enumerators)                                     \
};                                                                     \
                                                                       \
template <typename Source>                                             \
struct checked_enum_cast_impl<name, Source>                            \
{                                                                      \
    static name cast(Source s)                                      \
    {                                                                  \
        switch (s)                                                     \
        {                                                              \
        BOOST_PP_SEQ_FOR_EACH(X_DEFINE_SAFE_CAST_CASE, 0, enumerators) \
            return static_cast<name>(s);                               \
        default:                                                       \
            throw invalid_enum_cast(BOOST_PP_STRINGIZE(name));         \
        }                                                              \
        return name();                                                 \
    }                                                                  \
};                                                                  \
std::vector<name> MembersOf(name AnyItem) {     \
    return {BOOST_PP_SEQ_ENUM(enumerators)}; \
}; 
#pragma一次
#包括
#包括
#包括
//内部助手为选中的枚举强制转换提供部分专门化
模板
检查结构\u枚举\u强制转换\u执行;
//在强制转换失败时由checked_enum_强制转换引发的异常
结构无效\u枚举\u强制转换:std::超出\u范围
{
无效的枚举强制转换(常量字符*s)
:std::超出范围{}
};
//检查强制转换函数
模板
目标已检查\u枚举\u强制转换(源s)
{
返回选中的\u enum\u cast\u impl::do\u cast(s);
}
//帮助在checked cast函数中声明案例标签的内部帮助程序
#定义X_定义_安全_铸造_案例(r,数据,元素)案例元素:
//如何做到这一点?StackOverflow 11/30/14中提出的问题——请稍后再次查看。
#定义X_添加_到_TORET(r,数据,元素)TORET。向后推(元素)
//使用选中的强制转换函数定义枚举。
//name是要定义的枚举的名称
//枚举数是要定义的枚举数的预处理序列。
#定义密度(名称、枚举数)\
枚举名\
{                                                                      \
BOOST_PP_SEQ_枚举(枚举器)\
};                                                                     \
\
模板\
已检查结构\u枚举\u强制转换\u执行\
{                                                                      \
静态名称转换(源)\
{                                                                  \
开关\
{                                                              \
BOOST\u PP\u SEQ\u FOR_EACH(X_DEFINE\u SAFE\u CAST\u CASE,0,枚举数)\
返回静态_-cast(s)\
默认值:\
抛出无效的枚举强制转换(BOOST\u PP\u STRINGIZE(name))\
}                                                              \
返回名称()\
}                                                                  \
};                                                                  \
std::向量成员(名称AnyItem){\
返回{BOOST_PP_SEQ_ENUM(枚举数)}\
}; 
当我用这个声明一个枚举时(例如,语法是DENUM(SYSTEM_STATES,(Loading)(Running)(Finished));),每当包含声明的文件链接到多个对象时,MembersOf()就会生成一个链接器错误——甚至,例如,main.obj和someclass.obj。具体错误文本:

1>main.obj : error LNK2005: "class std::vector<enum SYSTEM_STATES,class std::allocator<enum SYSTEM_STATES> > __cdecl MembersOf(enum SYSTEM_STATES)" (?MembersOf@@YA?AV?$vector@W4SYSTEM_STATES@@V?$allocator@W4SYSTEM_STATES@@@std@@@std@@W4SYSTEM_STATES@@@Z) already defined in Controller.obj
1>UserInputProcessor.obj : error LNK2005: "class std::vector<enum SYSTEM_STATES,class std::allocator<enum SYSTEM_STATES> > __cdecl MembersOf(enum SYSTEM_STATES)" (?MembersOf@@YA?AV?$vector@W4SYSTEM_STATES@@V?$allocator@W4SYSTEM_STATES@@@std@@@std@@W4SYSTEM_STATES@@@Z) already defined in Controller.obj
1>C:\Users\UserName\Documents\MembersOf investigation\Debug\MembersOf investigation.exe : fatal error LNK1169: one or more multiply defined symbols found
1>main.obj:错误LNK2005:“类标准::向量cdecl成员(枚举系统状态)”(?成员@@YA?AV$vector@W4SYSTEM_STATES@@V$allocator@W4SYSTEM_STATES@@@std@@@std@@W4SYSTEM_STATES@@@Z)已在Controller.obj中定义
1> UserInputProcessor.obj:错误LNK2005:“类std::vector\uuuCDECL成员(枚举系统状态)”(?成员@@YA?AV$vector@W4SYSTEM_STATES@@V$allocator@W4SYSTEM_STATES@@@std@@@std@@W4SYSTEM_STATES@@@Z)已在Controller.obj中定义
1> C:\Users\UserName\Documents\MembersOf investigation\Debug\MembersOf investigation.exe:致命错误LNK1169:找到一个或多个多重定义符号
我知道,在几个月前,在我将SFML安装到我的系统上之前,它工作正常,但我不认为这是原因;我在一个甚至没有链接到SFML的测试平台项目中重现了这个问题


在使用上述枚举的头中声明的其他内容以及boost的其他用途都可以正常工作。

您应该将
成员标记为
内联
。您的另一个选择是将其标记为静态(正如@simon在评论中提到的)。这将链接,但可能会在使用该函数的每个编译单元中创建
MemberOf
的副本。相反,声明
MemberOf
inline
应该强制链接器将发出的函数合并为一个函数


我之所以说应该是因为我相信这种行为是由实现定义的。在实践中,我相信上述情况适用于所有主要的实现,包括MSVC。

就是这样!将其标记为内联工作!非常感谢。最后,我可以回到这个项目上工作了……非常欢迎:)如果您想了解更多关于
内联
和链接之间的相互作用,您可能会发现这个问题很有帮助: