2

通常从概念上讲,模板必须作为类型参数传递,编译器会抱怨,因为这不是合法的 c++ - 至少在 c++11 之前并包括在内(更新 II:除了参见最后一个非专用模板定义示例)

这些概念经常被使用并且应该有一个名字。如果不清楚我的意思,请参阅下面的代码示例。

我的第一个想法是这也可以称为传递不完整的类型,但这是不正确的。另一位用户还表示,他对此一无所知,并随意将其命名为模板参数的后期绑定。我认为他的术语很好地形象化了这个概念。

我的问题是你如何正确地调用这背后的成语或涉及的模板?

更新Kerrek 建议将成语模板命名为 rebinding 。此名称仅呈现少数 google 搜索结果。但是我认为这也是一个很好的名字,因为标准分配器将它们相关的包装内部类称为rebind

在以下示例中,您可以配置数据库是否使用maphashmap内部:

#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;
}

当然,欢迎使用其他方式重新绑定后期绑定模板参数的示例。

4

1 回答 1

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

这更具限制性:您的数据库现在不仅必须对所有内容使用相同的数据结构,而且数据结构还必须作为具有固定前两个参数“键类型”和“映射类型”的模板给出。

于 2013-11-02T03:25:42.557 回答