概念上,模板通常必须作为类型参数传递,并且编译器会抱怨,因为这不是合法的c ++ - 至少在包含c ++ 11之前(< strong>更新II:除了查看非专业模板定义的最后一个示例)
这些概念经常被使用,应该有一个名字。如果不清楚我的意思,请参阅下面的代码示例。
我的第一个想法是,这也可能被称为传递一个不完整的类型,但这是不正确的。另一位用户还声明他没有任何消息,并自由命名late binding of template arguments。我认为他的术语可以很好地形象化这个概念。
我的问题是你如何正确地调用这个或相关模板背后的成语?
更新 Kerrek建议命名成语模板重新绑定。此名称仅呈现一些谷歌搜索结果。但是我认为它也是一个非常好的名称,因为标准分配器调用它们相关的包装内部类重新绑定。
在以下示例中,您可以配置数据库是否在内部使用map
或hashmap
:
#include <map>
struct map_wrapper
{
template<typename K, typename V>
using type = std::map<K,V>;
};
template<typename storage>
struct my_database
{
typename storage::template type<int, int> x;
typename storage::template type<int, double> y;
};
main ()
{
my_database<map_wrapper> db;
db.x[0] = 1;
db.y[0] = 2.0;
}
或类似地
#include <map>
#include <boost/mpl/apply.hpp>
template <typename storage>
struct my_database
{
typename boost::mpl::apply<storage, int>::type x;
typename boost::mpl::apply<storage, double>::type y;
};
int main ()
{
my_database< std::map<int, boost::mpl::_1> > db;
db.x[0] = 1;
db.y[0] = 2.0;
}
更新II:令我尴尬的是,我不知道以下解决方案只是将模板作为参数传递给模板实例化。在这种特殊情况下,传递非类型是合法的。
#include <map>
#include <unordered_map>
template<template<typename...> class Storage>
struct my_database
{
Storage <long,char> x;
Storage <long,double> y;
};
int main ()
{
my_database< std::map > db1;
db1.x[0] = '1';
db1.y[0] = 2.2;
my_database< std::unordered_map > db2;
db2.x[0] = '1';
db2.y[0] = 2.2;
}
重新绑定或后期绑定模板参数的其他方法示例当然受到欢迎。
答案 0 :(得分:2)
您提供了模板,其中需要类型。
对于它的价值,GCC 4.8提供了一个不错的诊断:
template <typename> struct Foo;
template <typename> struct Bar;
int main()
{
Foo<Bar> x;
}
诊断:
In function ‘int main()’:
error: type/value mismatch at argument 1 in template parameter list for ‘template<class> struct Foo’
Foo<Bar> x;
^
error: expected a type, got ‘Bar’
(自从Clang开始制作非常好的错误消息后,GCC变得更好了,所以这可能是最近的;我想Clang也会在这里给出一个有用的错误。)
关于您更新的问题:制作容器适配器的典型方法,或者通常是需要您可以自定义的某个容器的类,是将整个容器作为模板参数传递:
template <typename XContainer, typename YContainer>
struct Database
{
XContainer xstorage;
YContainer ystorage;
};
Database<std::map<int, double>, std::unordered_map<std::string, double>> db;
db.xstorage[1] = 2.5;
db.ystorage["foo"] = 4.5;
这是最通用的解决方案,因为您可以使用符合您需要的任何类,而不需要该类具有任何特定结构。
作为替代方法(我不建议),如果您希望所有容器都是同一模板的模板特化,您可以直接将模板作为模板参数传递(一个 - 被叫模板模板参数):
template <template <typename, typename, typename...> class CTmpl,
typename XType,
typename YType>
struct Database
{
CTmpl<XType, double> x;
CTmpl<YType, double> y;
};
Database<std::map, int, std::string> db;
// as above
这是一个更严格的限制:您的数据库不仅现在必须为所有内容使用相同的数据结构,而且数据结构还有作为模板给出,前两个参数是固定的“密钥类型”和“映射类型”。