【问题标题】:Static template member array sizeof used in method方法中使用的静态模板成员数组 sizeof
【发布时间】:2015-05-21 15:44:12
【问题描述】:

我有一个带有静态成员数组的模板类和一个需要数组大小的方法。

template <int i>
struct Foo {
    static int data[];
    static int size() {
        return sizeof(data) / sizeof(data[0]);
    }
};

我想为每个模板特化不同地初始化数组。

template <>
int Foo<0>::data[] = { 0, 1, 2 };

只要我只在一个 cpp 文件中使用它,它就可以工作。但是如何在多个文件中使用呢?

如果我把初始化放到头部,链接会失败,因为:

multiple definition of `Foo<0>::data'

如果我将它放入其中一个 cpp 文件中,其他文件将无法编译,因为:

invalid application of ‘sizeof’ to incomplete type ‘int []’

我对不将数组更改为 std::vector 的解决方案感兴趣。

【问题讨论】:

  • 为什么不直接在data 所在的翻译单元中定义size()?
  • 我将在不同的文件中有几个专业化,但我不会在每个文件中都定义大小。
  • 可能是头文件中的通用文件和实现文件中的特化?

标签: c++ arrays templates initialization


【解决方案1】:

如果您将结构模板定义留在标题中,您可以在初始化数据的翻译单元中强制模板实例化,并在使用时使用 extern 阻止它,例如:

// imp.cc: initialization and instantiation
template <>
int Foo<0>::data[] = { 0, 1, 2 };
template struct Foo<0>;

// main.cc: extern declaration and usage:
template<> extern int Foo<0>::size ();
... Foo<0>::size () ...

(我已经用一个小例子和clang对其进行了测试。)

【讨论】:

    【解决方案2】:

    这对我有用:

    Foo.h:

    #ifndef FOO_H
    #define FOO_H
    
    template <int i>
    struct Foo {
        static int data[];
        static int size() {
            return sizeof(data) / sizeof(data[0]);
        }
    };
    
    #endif
    

    Foo-0.h:

    #ifndef FOO_0_H
    #define FOO_0_H
    
    #include "Foo.h"
    
    // Provide declarations of the members for 0
    template <> int Foo<0>::data[];
    template <> int Foo<0>::size();
    
    #endif
    

    Foo-0.cpp:

    #include "Foo-0.h"
    
    // Define the members for 0
    template <> int Foo<0>::data[] = {10, 20, 30};
    template <> int Foo<0>::size()
    {
       return sizeof(data) / sizeof(data[0]);
    }
    

    main.cpp:

    #include <iostream>
    
    #include "Foo-0.h"
    
    int main()
    {
        std::cout << Foo<0>::data[0] << std::endl;
        std::cout << Foo<0>::size() << std::endl;
    };
    

    输出:

    10
    3
    

    【讨论】:

    • 这个解决方案是否暗示您需要为 Foo::size() 的每个实例化提供定义?
    • @ComeRaczy,仅适用于您想专攻的人。您可以在Foo.h 中进行通用实现。
    • 如果我在 Foo-0.cpp 中注释掉 Foo::size() 的定义,ld 会抱怨对 Foo::size() 的未定义引用
    • @ComeRaczy,这是有道理的。由于template &lt;&gt; int Foo&lt;0&gt;::size(); 被声明为显式特化,因此必须显式实现。
    • @ComeRaczy,不可能仅提供 Foo&lt;0&gt;::data 的明确特化并依赖于 Foo&lt;0&gt;::size() 的通用实现。
    【解决方案3】:

    您可以尝试将其封闭在未命名的命名空间中,这将提供内部链接并绕过 `Foo::data' 的多重定义

    namespace{
    template <int i>
    struct Foo {
        static int data[];
        static int size() {
            return sizeof(data) / sizeof(data[0]);
        }
    };
    }
    

    【讨论】:

    • 为什么这个答案被否决了?它似乎解决了这个问题。这种情况有什么缺点吗?
    • 另一方面,我可以想象未来的维护者会不知道为什么将未命名的命名空间放置在那里。
    • @simon 的缺点是程序中实际上存在多个变量副本(修改数组的值将是一个问题)。维护问题值得在代码中发表评论。我也对投反对票感到惊讶。
    • 没想到,数组的实际代码是不变的。
    • @simon 带有一个 const 数组,未命名的命名空间将起作用。但是,请确保以后没有人添加非常量静态变量(如果有这种需要,则必须拆分类)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多