【发布时间】:2017-11-23 20:08:38
【问题描述】:
这是我正在尝试创建的池化对象的最小工作示例(显然功能不完整 - 我只是想说明我遇到的问题)
我有一个类模板Storage,其中包含aligned_storage:
template<typename T, std::size_t N>
struct Storage
{
std::aligned_storage_t<sizeof(T), alignof(T)> data[N];
};
然后我有一个基类模板PoolObj,它使用operator new从模板参数T的静态类成员中分配:
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 成员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];
- 为什么
Storage中的T对于Foo来说是完整的,而对于Bar<int>等来说却是不完整的? - 是否有可能实现我在这里希望的设计?
完整示例如下: (and on coliru)
#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;
}
编辑:
有趣的是this works fine in clang (coliru)。
- 哪个编译器是正确的?
- 这是 gcc 中的错误吗?
第二次编辑:
根据 cmets,它也可以在 VS2017 中找到。因此,我想我倾向于 gcc 中的错误?
【问题讨论】:
-
我猜这是因为您使用 Bar
作为类 Bar 定义的一部分。不确定是否足以使其成为官方答案。但这个错误确实有道理。 -
补充一点,如果编译器在
Bar<T>的定义过程中试图了解静态成员池的大小,那么此时Bar<T>是不完整的。当它会检查std::aligned_storage_t<sizeof(T), alignof(T)>以了解池的大小时,Bar<T>(在此上下文中为 T)仍然是不完整的,并且取 sizeof 不完整类型是非法的。 -
@OriBS
Storage仅在我们声明Bar<int>时为Bar<T>实例化。在它被实例化的那一刻,它肯定有完整的类型吗?此外,它在 clang 下工作 - 哪个编译器是正确的? -
@OriBS:我不会在这里看到为什么类型只会在模板案例中不完整。
-
顺便说一句,您的示例也可以使用 Visual Studio 2017 进行编译