C++ 模板模板参数

5
#include <iostream>

using namespace std;

template <typename T = int>
struct Foo {
    T t;
    Foo() { cout << "Foo" << endl; }
};

template <typename T>
struct Baz {
    T t;
    Baz() { cout << "Baz" << endl; }
};

template <typename T>
struct Bar {
    T t;
    Bar() { cout << "Bar" << endl; }
};

template <template <typename X> class T>
struct Bar {
    T data;
    Bar() : data() { cout << "Bar" << endl; }
};

int main()
{
    Bar<Foo<>> a;

    Bar<Baz<float>> b;

    Bar<int> c;

    return 0;
}

我刚开始学习模板。我非常困惑模板模板参数。我知道你可以将模板作为参数传递。在我的 Bar 模板类中,当它接收到一个模板模板参数时,<typename X> 代表什么?typename Xclass T 的模板参数吗?

template <template <typename X> class T>
struct Bar {
    T data;
    Bar() : data() { cout << "Bar" << endl; }
};

此外,在主函数中调用模板参数时,我得到了关于 Bar 没有默认构造函数的错误。为什么会这样呢?
3个回答

3

typename X只是模板模板参数签名的一部分,你可以写成template<template<typename> class T>(不需要T的参数名称)。

由于T本身是一个模板,在你可以将其用作类之前,你需要实例化它。该签名告诉你模板需要被实例化的内容,在这种情况下,它需要一个类型名称。

template<typename X>
struct GenericThing
{
    X data;
};

template<template<typename> class T, typename E>
struct Bar
{
    T<E> sub; // instantiate T with E
    Bar() : sub() { cout << "Bar" << endl; }
};

int main()
{
    Bar<GenericThing, int> intbar;
    Bar<GenericThing, float> floatbar;
    return 0;
}

3

模板模板参数允许你把模板传递给其他模板。

它们不是具体的类型,需要按顺序参数化才能实例化它们。

当我的Bar模板类接收一个模板模板参数时,<typename X>代表什么?

来自标准文献[basic.scope.temp]

模板模板参数的模板参数名的声明区域是引入该名称的最小模板参数列表。

这基本上意味着该名称仅在该模板模板的参数列表内有效。

对于许多情况,只需使用typename而不带名称作为模板模板参数即可满足要求,但名称可以用于文档化代码。

然而,如果另一个非类型模板参数依赖于它,则给它一个名称会有用。

例如:template <template <typename X, X> typename Y>

关于你的示例代码,你在第二个Bar声明中有两个问题。首先,Bar已经被声明为接受类型,而不是模板。你的第二个声明与它声明为接受模板发生冲突。

你在这里需要的是一个Bar的特化,其中特化解析为单个类型,与主模板匹配。例如:

template <template <typename> class T,typename Y>
struct Bar<T<Y>> {
    T<Y> data;
    Bar() : data() { cout << "Bar" << endl; }
};

重要的是要注意这里的专业化模板参数可以是您需要的任何内容。在struct Bar之后的部分必须与主模板匹配。在专业化中的所有参数都将从传递给Bar实例化的模板参数的类型中推导出来。
您的第二个问题是声明Bar的成员为T类型。在第二种情况下,T是一个模板,而您无法实例化一个没有参数化的模板。
以下是使用Bar的专业化版本的代码示例。
#include <iostream>

using namespace std;

template <typename T = int>
struct Foo {
    T t;
    Foo() { cout << "Foo" << endl; }
};

template <typename T>
struct Baz {
    T t;
    Baz() { cout << "Baz" << endl; }
};

template <typename T>
struct Bar {
    T t;
    Bar() { cout << "Bar" << endl; }
};



template <template <typename > class T,class Y>
struct Bar<T<Y>> 
{
    T<Y> data;
    Bar() : data() { cout << "Bar Specialization" << endl; }
};

int main()
{
    Bar<Foo<>> a; //matches the specialization with T = template<typename> Foo and Y=int

    Bar<Baz<float>> b; //matches the specialization with T = template<typename> Baz and Y=float

    Bar<int> c; //matches the primary template with T=int

    return 0;
}

演示


-1
template <typename T>
void func_template(T& con) {
    for (const auto& c : con)
        std::cout << c << std::endl;
}

/*
        Nested Templates
        template <
            template < 
                // # of type args that will be included in the nested template
                typename,
                ...
            >
            // # of different types yo
            typename T1,
            ...
            typename TN
        >
    */

template <template<typename, typename> typename V, typename T>
void func_template3(V<T, std::allocator<T>>& vec) {
    for (const auto& elem : vec)
        std::cout << elem << std::endl;
}

template <template<typename, typename, typename, typename> typename M, typename T1, typename T2>
void func_template4(M<T1, T2, std::less<T1>, std::allocator<std::pair<const T1, T2>>> & dict) {
    for (const auto& pair : dict)
        std::cout << pair.first << " " << pair.second << std::endl;
}

我一个月前才学习了C++,所以请多包容。上面是我个人的看法。func_template3和func_template4提供了一个打印任何类型的向量和映射的模板示例。我发现注意VS“没有与函数模板'XXXX'匹配的参数列表错误”对于确定应该包含在模板中的数据结构的内置类型的组成非常有用。

例如:

在实现func_template4之前,我将std::map变量用作func_template3的参数,然后VS提示我以下错误enter image description here

因此,在实现funct_template4时,我基本上使用错误的"arguments types are:(..."部分来指导我应该包含哪些其他内置类型。

我听说过实现嵌套模板通常是不必要的,因为它可以通过func_template1实现;但是,我有些不同意,因为您在func_template1中编写的代码实际上很大程度上取决于您打算将模板与哪种数据结构一起使用。这只是我这个C++新手的两分钱。


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