【问题标题】:Visual Studio 2013: linker errors with custom enumerations?Visual Studio 2013:自定义枚举的链接器错误?
【发布时间】:2015-07-24 01:42:47
【问题描述】:

我使用以下由 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)}; \
}; 

当我用这个声明一个枚举时(例如,语法是 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

我知道这几个月前在我的系统上安装 SFML 之前可以正常工作,但我认为这不是原因;我在一个测试平台项目中重现了这个问题,我什至没有链接到 SFML。

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

【问题讨论】:

    标签: c++ boost visual-studio-2013 enums linker


    【解决方案1】:

    您应该标记MemberOf inline。您的另一个选择是将其标记为static(如@simon 的评论中所述)。这将链接,但它可能会在每个使用该函数的编译单元中创建MemberOf 的副本。改为声明 MemberOf inline 应该强制链接器将发出的函数合并为一个。

    我说应该的原因是因为我相信这种行为是实现定义的。在实践中,我相信上述所有主要实现都是正确的,包括 MSVC。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-15
    • 2016-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-06
    相关资源
    最近更新 更多