模板化的递归数据类型

时间:2012-03-25 13:30:15

标签: c++ templates g++ c++11

我有一个这样的递归数据类型:

template<typename T>
struct SomeType {
    std::map<T, SomeType<T>> mapping;
};

SomeType<int> foo;

这样可以正常工作,但将std::map替换为std::unordered_map会因类型不完整而导致编译错误。我(或gcc)在某个地方犯了错误吗?或者这只是标准的一部分?

我还希望内部容器由模板参数(例如std::stackstd::queue)确定,但我无法找到一种方法来实现它,因为这需要SomeType来已定义。

不完整的例子:

template<typename T, typename C = std::map<T, SomeType<[???]>>>
struct SomeType {
    C mapping;
};

SomeType<int, [???]> foo;

我知道这可以通过运行时间接完成,但这不是我想要的。

3 个答案:

答案 0 :(得分:7)

您的课程在其定义的最终}之前的任何地方都是不完整的。因此mapping成员在其类型的模板参数中使用了不完整的类型SomeType

The standard does not allow this, and it is pure luck that it works with some STL containers.

你的第二个问题属于同样的答案 - 首先这样做是违法的。

答案 1 :(得分:4)

出于显而易见的原因,您无法使用递归默认参数定义模板。您也无法在不完整类型上实例化标准库容器模板,因为标准是这样说的(否则它是未定义的行为)。但是,通常的PIMPL习惯可能会有所帮助:

#include <map>
#include <memory>
template <typename T> class SomeType
{
    typedef std::map<T, SomeType<T>> map_type;
    typedef std::unique_ptr<map_type> map_ptr;
    map_ptr pimpl;
public:
    SomeType() : pimpl(new map_type) { }
};

答案 2 :(得分:3)

虽然您不能将不完整类型与容器一起使用,但您可以使用智能指针来执行此操作。 虽然您无法使用未定义的类型参数创建模板类型,但您可以在此处使用一些技巧:

template<typename T, template <typename U, typename V, typename... Args> class Container = std::unordered_map >
struct SomeType {
    Container<T, std::unique_ptr<SomeType> > mapping;
};