【问题标题】:Template specialization with static char* array member, instanciation in multiple units具有静态 char* 数组成员的模板特化,多个单元的实例化
【发布时间】:2014-03-08 15:49:53
【问题描述】:

我有一个模板结构来存储 static char* 数组,如下所示:

template<typename T>
struct EnumStrings {
    static const char* const data[];
};

我想这样专门化它:

template<> const char* const EnumStrings<SomeType>::data[] =
    {"item1", "item2", "item3", "item4"};

如果我将此实例化放在头文件中,并且此头文件包含在多个单元中,则会收到此链接器错误:

multiple definition of `EnumStrings<SomeType>::data'

现在,如果我将此实例化放在 cpp 文件中,则使用 data 数组的其他代码无法使用 sizeof 运算符推断其大小,从而导致以下错误:

error: invalid application of ‘sizeof’ to incomplete type ‘const char* const []’

因为我需要能够迭代这个数组,所以,我被卡住了......有什么建议吗?当然,我不想在某个地方指定数组的大小,但也许这是唯一的可能性。

【问题讨论】:

  • 或许可以考虑使用带有静态成员函数的std::array 来代替?
  • 我已经实现了完全相同的行为。但是我的实现使用了一个定义良好的接口,如下所示:std::string ToString(const T&amp; enumValue);。在两个std::maps 下使用类似于“双向地图”。通过将公共代码和代码拆分为两个单独的类(Ènum&lt;T&gt;EnumImpl&lt;T&gt;),一个人不必复制粘贴公共代码(std::map,查找等;这是另一个非常重要的原因是惰性初始化,因为这些类的使用系统对于init来说非常复杂),但只需要专门化EnumImpl&lt;T&gt;::Initialize()
  • 当然我的方法有点慢(因为std::map 不是静态的)。但是我的用例与运行时无关,所以这不是一个大问题,在这种情况下,我更喜欢干净的代码而不是速度。

标签: c++ arrays templates static


【解决方案1】:

在 C++11 中的以下作品:

// In header:

class SomeType;
template<typename T> struct EnumStrings;

template<>
struct EnumStrings<SomeType> {
    static constexpr
    const char* const data[] =
        {"item1", "item2", "item3", "item4"};
};

// in cpp, if address of data is taken.

constexpr
const char* const EnumStrings<SomeType>::data[];

【讨论】:

    【解决方案2】:

    你应该划分data数组特化的声明和定义。把它放在你的头文件中:

    template<typename T>
    struct EnumStrings {
        static const char* const data[];
    };
    
    // declaration of `data` array specialization
    template<> const char* const EnumStrings<SomeType>::data[4];
    

    这在您的cpp 文件中:

    // definition of `data` array specialization
    template<> const char* const EnumStrings<SomeType>::data[] =
        {"item1", "item2", "item3", "item4"};
    

    【讨论】:

    • 很遗憾,这行不通,因为我需要知道data 在其他单位中的大小。这导致了我提到的第二个错误:error: invalid application of ‘sizeof’ to incomplete type ‘const char* const []’
    • @OlivierB 只需在*.h 文件中添加数组的大小。我已经更正了我的答案。
    • 嗯,有了这个,我仍然收到multiple definition of 'EnumStrings&lt;SomeType&gt;::data' 错误...我真的不明白为什么?
    • @OlivierB 你用什么编译器?
    • 我使用的是 gcc 版本 4.7.2 (Debian 4.7.2-5)
    【解决方案3】:

    您可以将数据数组特化的结构声明和定义放在匿名命名空间中。然后结构将具有内部链接,这应该可以防止多个定义错误。

    namespace {
    template<typename T>
    struct EnumStrings {
        static const char* const data[];
    };
    template<> const char* const EnumStrings<int>::data[] =
        {"item1", "item2", "item3", "item4"};
    }
    

    【讨论】:

    • 如果在多个单元中实例化,我看不出这会如何改变?我仍然收到我提到的第一个错误:multiple definition of 'EnumStrings&lt;SomeType&gt;::data'
    • @OlivierB 这个想法是模板没有外部链接,所以这应该可以防止多个定义错误。 (EnumStrings&lt;Foo&gt;EnumStrings&lt;Foo&gt; 在不同的编译单元中编译时是不同的类)。
    • 我用 a.h 中的 struct 以及包括它的 a.cpp 和 b.cpp 测试了这个设置,并且匿名命名空间按预期防止了多个定义错误。没有匿名命名空间编译器会发出你提到的错误。
    • 有效!我选择这个答案是因为事实证明@Constructors 的答案在 Visual Studio 2012 上不起作用。
    猜你喜欢
    • 1970-01-01
    • 2011-04-11
    • 2020-10-27
    • 2017-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-20
    • 2013-05-30
    相关资源
    最近更新 更多