具有模板模板参数的模板定义,可用于特化类,例如,std::vector<std::string>或std::map<std::tree>。

6
我希望创建一个模板类,能够容纳任何组合的容器和元素。例如,像 std::vector<std::string> 或者 std::map<std::tree> 这样的组合。
我已经尝试了许多组合,但必须承认,模板的复杂性让我不知所措。我最接近成功的尝试是这样的:
template <class Vector, template <typename, class Containee = std::string> class Container>
class GenericContainer
{
    Container<Containee> mLemario;
};

尽管到目前为止它可以编译,但当我想要实例化它时,会收到许多错误。
MyContainer<std::vector, std::string> myContainer;

我使用的方法是否正确,可以创建那种类?

1
没有 std::tree 这样的东西,因此也就不存在 std::map<std::tree>。另外,std::map 至少需要两个参数:keyvalue,即 std::map<key,value>。那么你认为 std::map 的容器是什么?它的 keyvalue 还是 std::pair<key,value>(这实际上是 std::map::value_type 给出的)? - Walter
1
它将支持哪些功能?你将如何使用它?我问这个问题是因为不同的容器提供非常不同的、复杂度不同的功能。它们不能互换。总的来说,我认为这是一个不好的想法。 - Andriy Tylychko
3个回答

8
对于 std::vector(等等)@songyuanyao提供了一个很好的答案。但是由于您还提到了std::map,所以我将添加一个简单的扩展 @songyuanyao的答案,在线
#include <iostream>
#include <vector>
#include <string>
#include <map>

template <template <typename...> class Container, typename Containee = std::string, typename... extras>
class GenericContainer
{
    Container<Containee, extras ...> mLemario;
    // Use 'Containee' here (if needed) like sizeof(Containee) 
    // or have another member variable like: Containee& my_ref.
};

int main()
{
    GenericContainer<std::vector, std::string> myContainer1;
    GenericContainer<std::vector, std::string, std::allocator<std::string>> myContainer2; // Explicitly using std::allocator<std::string>
    GenericContainer<std::map, std::string, int> myContainer3; // Map: Key = std::string, Value = int
}

太好了!正如我所料,这不是给初学者的。目前为止它已经编译通过了。 - Hola Mundo
我发现在模板声明之外实例化函数极其困难:我正在尝试这样做:template <template <typename...> class Container,typename Containee = std::string,typename ... extras> Containee GenericContainer<>::transform_word(const Containee&word) {} 但是无论我放什么在GenericContainer<...>里面,它都无法编译。 - Hola Mundo
它有效。我会创建另一个问题来实现我的最后一个愿望:函数专门化。 - Hola Mundo
1
-1 这是错误的建议/设计:Containee 不需要作为 template 参数,因为它可以直接使用 Container::value_type 来确定。同样地,extras 也不需要,因为它在 Container 中是隐含的(并且在你的类中没有被使用)。 - Walter
对于 Container=std::map,你被迫要有 Containee=Key。这没有任何意义。 - Walter
显示剩余2条评论

4
我希望创建一个模板类,可以容纳任何容器和被包含的元素的组合。
您应该使用参数包作为模板模板参数ContainerContainee,然后它们可以与任意数量/类型的模板参数一起使用。例如:
template <template <typename...> class Container, typename... Containee>
class GenericContainer
{
    Container<Containee...> mLemario;
};

那么

GenericContainer<std::vector, std::string> myContainer1;
GenericContainer<std::map, std::string, int> myContainer2;

1

标准容器声明其元素类型的名称,因此您可以编写

template<typename Container>
class GenericContainer
{
    using Containee = typename Container::value_type;
};

您可以这样使用它:

int main()
{
    GenericContainer<std::vector<std::string>> myContainer;
}

您可以使用非默认分配器来使用这些容器,但不要轻易地创建具有不同元素类型的类似容器。这可能或可能不是您的障碍。

2
我认为你的意思是Container::value_type - Caleth
1
不完全是我想要的,因为我希望std::string也是一个参数。 - Hola Mundo
@HolaMundo 首先,您没有明确指定这一点。其次,您可以轻松创建一个模板别名声明来处理这个问题。 - Walter
感谢@Walter的编辑 - 我应该更加小心! - Toby Speight
@Walter 是的,我在我的问题的第一行中提到了:我想创建一个模板类,可以容纳任何容器和内容。例如,std::vectorstd::string或std::mapstd::tree。 - Hola Mundo
1
@HolaMundo 是的,但像 std::vector<std::string> 这样的类型已经是容器和包含物 - Walter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接