Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 静态类模板成员:无效的应用程序‘;尺寸’;不完整类型_C++_Templates - Fatal编程技术网

C++ 静态类模板成员:无效的应用程序‘;尺寸’;不完整类型

C++ 静态类模板成员:无效的应用程序‘;尺寸’;不完整类型,c++,templates,C++,Templates,下面是我试图创建的池对象的一个最小工作示例(显然不是功能完整的-我只是想说明我遇到的问题) 我有一个类模板存储,它包含对齐的存储: template<typename T, std::size_t N> struct Storage { std::aligned_storage_t<sizeof(T), alignof(T)> data[N]; }; 现在,我有了一个从PoolObj继承的类,它有一个静态存储成员池,因此当我使用new创建实例时,我将从池中获得存

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

我有一个类模板
存储
,它包含
对齐的存储

template<typename T, std::size_t N>
struct Storage
{
    std::aligned_storage_t<sizeof(T), alignof(T)> data[N];
};
现在,我有了一个从
PoolObj
继承的类,它有一个静态
存储
成员
,因此当我使用
new
创建实例时,我将从池中获得存储

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

Storage<Foo, 10> Foo::pool {};
但是,现在我正在尝试启用
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 {};
编辑:

有趣的是

  • 哪个编译器是正确的
  • 这是gcc中的错误吗
第二次编辑:

根据评论,它也适用于VS2017。因此,我想我倾向于gcc中的一个bug

哪个编译器是正确的

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

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

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

静态成员变量是一个声明,而不是一个定义,因此clang是正确的

也就是说,这两个编译器在决定什么是“实例化声明而不是定义”和“需要成员定义存在的上下文,或者成员定义的存在是否会影响程序的语义”时都表现得很疯狂(你可以在这里找到很多类似于最近的情况)


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

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
模板
结构栏:PoolObj
{
静态存储和池;
};
模板
存储&&Bar::池=存储{};//注意,这里的临时生命周期是延长的

这似乎说服了clang和gcc避免实例化对齐的存储(应该是这样)。

我想这是因为您将Bar用作类Bar定义的一部分。不太确定,不足以作为正式答复。但是这个错误是有道理的。再加上一点,如果编译器在定义
Bar
期间试图理解静态成员池的大小,那么此时
Bar
是不完整的。当它检查
std::aligned_storage\u t
以了解池的大小时,
Bar
(在本上下文中为t)仍然不完整,并且对不完整类型获取大小是非法的。@OriBS
storage
仅在声明
Bar
时为
Bar
实例化。在它被实例化的时候,它肯定有完整的类型?此外,它在叮当声下工作-哪个编译器是正确的?@OriBS:我在这里不明白为什么只有模板case的类型才是不完整的。顺便说一句,您的示例也可以用visual studio 2017编译
$ ./a.out
new T
delete T
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];
#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;
}
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