模板重新绑定与后期模板绑定或如何调用后备模板中的模板

时间:2013-11-02 03:24:18

标签: c++ templates nomenclature

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

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

我的第一个想法是,这也可能被称为传递一个不完整的类型,但这是不正确的。另一位用户还声明他没有任何消息,并自由命名late binding of template arguments。我认为他的术语可以很好地形象化这个概念。

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

更新 Kerrek建议命名成语模板重新绑定。此名称仅呈现一些谷歌搜索结果。但是我认为它也是一个非常好的名称,因为标准分配器调用它们相关的包装内部类重新绑定

在以下示例中,您可以配置数据库是否在内部使用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;
}

更新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;
}

重新绑定后期绑定模板参数的其他方法示例当然受到欢迎。

1 个答案:

答案 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

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