通常,从概念上讲,模板必须作为类型参数传递,并且编译器会提示,因为这不是合法的 c++ - 至少在 c++11 之前(<强>更新II:除了参见非专用模板定义的最后一个示例)
这些概念经常使用,应该有一个名称。如果不清楚我的意思,请参阅下面的代码示例。
我的第一个想法是,这也可以称为传递不完整类型,但这是不正确的。另一位用户也表示,他对此无话可说,并随意将其命名为late binding of template arguments。 。我认为他的术语很好地形象化了这个概念。
我的问题是你如何正确调用这个背后的习惯用法或涉及的模板?
更新 Kerrek 建议将习语命名为模板重新绑定(bind)。这个名字只呈现一些谷歌结果。不过,我认为这也是一个非常好的名称,因为标准分配器将其相关的包装内部类称为重新绑定(bind)。
在以下示例中,您可以配置数据库是否在内部使用 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;
}
更新二:令我尴尬的是,我不知道以下解决方案,它只是将模板作为参数传递给模板实例化。在这种特殊情况下,传递非类型是合法的。
#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;
}
当然欢迎重新绑定(bind)或后期绑定(bind)模板参数的其他方法示例。
最佳答案
您已经提供了一个模板,其中需要类型。
就其值(value)而言,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;
这是最通用的解决方案,因为您可以使用任何适合您需求的类,而不要求该类具有任何特定的结构。
作为替代方案(我不推荐),如果您希望所有容器都是同一模板的模板特化,您可以直接将模板作为模板参数传递(一个 so - 称为模板模板参数):
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
这是一个更加严格的限制:您的数据库现在不仅必须对所有内容使用相同的数据结构,而且数据结构还必须作为具有固定前两个参数的模板给出“键类型”和“映射类型”。
关于c++ - 模板重新绑定(bind)与后期模板绑定(bind)或如何调用小 pig 支持类型中的模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19738649/