为了账号安全,请及时绑定邮箱和手机立即绑定

模板参数的一些用途是什么?

模板参数的一些用途是什么?

C++
繁星淼淼 2019-06-29 17:12:57
模板参数的一些用途是什么?我看到了一些使用模板参数(即以模板作为参数的模板)来进行基于策略的类设计的C+示例。这项技术还有什么其他用途?
查看完整描述

3 回答

?
Helenr

TA贡献1780条经验 获得超4个赞

我认为您需要使用模板语法来传递一个参数,该参数的类型依赖于另一个模板,如下所示:

template <template<class> class H, class S>void f(const H<S> &value) {}

这里,H是一个模板,但我希望这个函数能够处理H.

:我已经编程c+很多年了,而且只需要一次。我发现它是一个很少需要的特性(当然,当您需要它时,它非常方便!)

我一直在努力想出好的例子,老实说,大多数时候这是不必要的,但让我们想一个例子。让我们假装std::vector typedef value_type.

那么,如何编写一个可以为向量元素创建正确类型的变量的函数呢?这样就行了。

template <template<class, class> class V, class T, class A>void f(V<T, A> &v) {
    // This can be "typename V<T, A>::value_type",
    // but we are pretending we don't have it

    T temp = v.back();
    v.pop_back();
    // Do some work on temp

    std::cout << temp << std::endl;}

*我们std::vector有两个模板参数,类型和分配器,所以我们必须同时接受它们。幸运的是,由于类型推断,我们不需要显式地写出确切的类型。

你可以这样用:

f<std::vector, int>(v); // v is of type std::vector<int> using any allocator

或者更好的是,我们可以用:

f(v); // everything is deduced, f can deal with a vector of any type!

更新:即使这个人为的例子,虽然具有说明性,但由于c+11的引入,已经不再是一个令人惊奇的例子了。auto..现在,可以将相同的函数编写为:

template <class Cont>void f(Cont &v) {

    auto temp = v.back();
    v.pop_back();
    // Do some work on temp

    std::cout << temp << std::endl;}

这就是我更喜欢写这种类型的代码的方式。


查看完整回答
反对 回复 2019-06-29
?
临摹微笑

TA贡献1982条经验 获得超2个赞

实际上,模板参数的使用是相当明显的。一旦您了解到C+stdlib存在不为标准容器类型定义流输出操作符的漏洞,就可以编写如下内容:

template<typename T>static inline std::ostream& operator<<(std::ostream& out, std::list<T> const& v){
    out << '[';
    if (!v.empty()) {
        for (typename std::list<T>::const_iterator i = v.begin(); ;) {
            out << *i;
            if (++i == v.end())
                break;
            out << ", ";
        }
    }
    out << ']';
    return out;}

然后你会发现向量的代码是一样的,因为Forward_List是一样的,实际上,即使对于多种地图类型,它仍然是一样的。除了元接口/协议之外,这些模板类没有任何共同之处,使用模板参数可以捕获所有模板的共性。但是,在继续编写模板之前,值得检查一个引用,以回顾序列容器接受2个模板参数-用于值类型和分配器。虽然分配器是默认的,但我们仍然应该在模板操作符<:

template<template <typename, typename> class Container, class V, class A>std::ostream& operator<<(std::ostream& out, Container<V, A> const& v)...

瞧,这将自动工作,所有现在和未来的序列容器符合标准协议。要将映射添加到混合中,需要查看一下引用,注意它们接受4个模板参数,因此我们需要操作符<上面的另一个版本,使用4-Arg模板param。我们还会看到,std:偶对尝试使用2-Arg操作符<for我们前面定义的序列类型来呈现,因此我们将只为std:偶数提供专门化。

顺便说一句,使用C+11(允许可变模板)(因此应该允许可变模板args),可以让单个操作符<来统治所有这些模板。例如:

#include <iostream>#include <vector>#include <deque>#include <list>template<typename T, template<class,class...> class C, class... Args>std::ostream& operator <<(std::ostream& os, const C<T,Args...>& objs){
    os << __PRETTY_FUNCTION__ << '\n';
    for (auto const& obj : objs)
        os << obj << ' ';
    return os;}int main(){
    std::vector<float> vf { 1.1, 2.2, 3.3, 4.4 };
    std::cout << vf << '\n';

    std::list<char> lc { 'a', 'b', 'c', 'd' };
    std::cout << lc << '\n';

    std::deque<int> di { 1, 2, 3, 4 };
    std::cout << di << '\n';

    return 0;}

输出量

std::ostream &operator<<(std::ostream &, const C<T, Args...> &) [T = float, C = vector, Args = <std::__1::allocator<float>>]1.1 2.2 3.3 4.4 std::ostream &operator<<(std::ostream &, const C<T, Args...> &) [T = char, C = list, Args = <std::__1::allocator<char>>]a b c d 
std::ostream &operator<<(std::ostream &, const C<T, Args...> &) [T = int, C = deque, Args = <std::__1::allocator<int>>]1 2 3 4


查看完整回答
反对 回复 2019-06-29
?
天涯尽头无女友

TA贡献1831条经验 获得超9个赞

下面是一个简单的例子“现代C+设计-通用编程和应用设计模式”安德烈·亚历山德雷斯库:

他使用带有模板参数的类来实现策略模式:

// Library codetemplate <template <class> class CreationPolicy>class WidgetManager : public CreationPolicy<Widget>{
   ...};

他解释说:通常,宿主类已经知道或可以很容易地推断策略类的模板参数。在上面的示例中,WidgetManager总是管理Widget类型的对象,因此要求用户在CreationPolicy的实例化中再次指定Widget是多余的,而且可能很危险。在这种情况下,库代码可以使用模板参数来指定策略。

其效果是客户端代码可以更优雅地使用“WidgetManager”:

typedef WidgetManager<MyCreationPolicy> MyWidgetMgr;

而不是缺乏模板参数的定义所需要的更麻烦、更容易出错的方式:

typedef WidgetManager< MyCreationPolicy<Widget> > MyWidgetMgr;


查看完整回答
反对 回复 2019-06-29
  • 3 回答
  • 0 关注
  • 667 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信