静态类模板成员:“sizeof”对不完整类型的无效应用

2023-12-10

这是我试图创建的池对象的最小工作示例(显然功能不完整 - 我只是想说明我遇到的问题)

我有一个类模板Storage其中包含aligned_storage:

template<typename T, std::size_t N>
struct Storage
{
    std::aligned_storage_t<sizeof(T), alignof(T)> data[N];
};

然后我有一个基类模板PoolObj它从模板参数的静态类成员中分配T using operator new:

template<typename T>
struct PoolObj
{
    static void* operator new(std::size_t size)
    {
        std::cout << "new T\n";
        return &T::pool.data[0];
    }

    static void operator delete(void* p, std::size_t size)
    {
        std::cout << "delete T\n";
    }
};

现在我有一个继承自的类PoolObj,并且有一个静态Storage member pool,这样当我使用创建实例时new,我将从池中获取存储空间。

struct Foo : PoolObj<Foo>
{
    static Storage<Foo, 10> pool;
};

Storage<Foo, 10> Foo::pool {};

这一切都很好:

int main()
{
    Foo* f = new Foo();
    delete f;
    return 0;
}
$ ./a.out
new T
delete T

然而,现在我正在尝试做一个PoolObj已启用类模板:

template<typename T>
struct Bar : PoolObj<Bar<T>>
{
    static Storage<Bar<T>, 10> pool;
};

template<typename T>
Storage<Bar<T>, 10> Bar<T>::pool {};

这不起作用

int main()
{
    Bar<int>* b = new Bar<int>();
    delete b;
    return 0;
}

尝试编译时出现以下错误:

In instantiation of ‘struct Storage<Bar<int>, 10ul>’:
   required from ‘struct Bar<int>’
 error: invalid application of ‘sizeof’ to incomplete type ‘Bar<int>’
  std::aligned_storage_t<sizeof(T), alignof(T)> data[N];
  • Why is T in Storage完成为Foo,但不完整Bar<int> et al?
  • 在这里可以实现我所希望的设计吗?

完整示例如下: (以及科利鲁)

#include <type_traits>
#include <cstddef>

template<typename T, std::size_t N>
struct Storage
{
    std::aligned_storage_t<sizeof(T), alignof(T)> data[N];
};

template<typename T>
struct PoolObj
{
    static void* operator new(std::size_t size)
    {
        return &T::pool.data[0];
    }

    static void operator delete(void* p, std::size_t size)
    {
    }
};

struct Foo : PoolObj<Foo>
{
    static Storage<Foo, 10> pool;
};

Storage<Foo, 10> Foo::pool {};

template<typename T>
struct Bar : PoolObj<Bar<T>>
{
    static Storage<Bar<T>, 10> pool;
};

template<typename T>
Storage<Bar<T>, 10> Bar<T>::pool {};

int main()
{
    Foo* f = new Foo();
    delete f;

    Bar<int>* b = new Bar<int>();
    delete b;

    return 0;
}

Edit:

有趣的是这在 clang (coliru) 中工作得很好.

  • 哪个编译器是正确的?
  • 这是 gcc 中的错误吗?

第二次编辑:

根据评论,它在 VS2017 中也能工作。因此,我想我倾向于 gcc 中的错误?


哪个编译器是正确的?

一般来说,相关的措辞应该是

[温度inst-2]类模板特化的隐式实例化会导致声明的隐式实例化,但不是定义、默认参数或类成员函数、成员类、作用域成员枚举、静态数据成员、成员模板和友元的 noexcept 说明符

and

[温度inst-3]除非类模板或成员模板的成员已显式实例化或显式特化,否则当在需要成员定义存在的上下文中引用特化时,或者如果存在定义时,会隐式实例化成员的特化。该成员影响程序的语义;尤其,静态数据成员的初始化(以及任何相关的副作用)不会发生,除非静态数据成员本身的使用方式需要静态数据成员的定义存在.

静态成员变量是声明而不是定义,所以 clang 是正确的。

也就是说,两个编译器在决定什么时都会表现得很疯狂”实例化声明但不实例化定义" and "要求成员定义存在的上下文,或者成员定义的存在是否影响程序的语义“意思是(你可以在这里找到很多极端情况,比如this最近)。


作为解决方法,您可以使用静态引用

template<typename T>
struct Bar : PoolObj<Bar<T>>
{
    static Storage<Bar<T>, 10>&& pool;
};

template<typename T>
Storage<Bar<T>, 10>&& Bar<T>::pool = Storage<Bar<T>, 10>{}; // note, the temporary is lifetime-extended here

这似乎说服 clang 和 gcc 避免实例化aligned_storage(因为它应该是这样)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

静态类模板成员:“sizeof”对不完整类型的无效应用 的相关文章

随机推荐