填坑吧,模板君

正如上一篇博客所说,普通C++语法中的引用在模板中往往是无效的。除非像这样显式地说明模板参数是引用:

template<typename T>
std::string toString(const T& x)
{
    std::stringstream ss;
    ss << x;
    return ss.str();
}

然而,有时我们并不总希望所有的类型都以引用的方式传递参数,为此只能为每一个必须要传值的参数类型写一个模板的特化。

显然,模板库自己是不可能知道某个模板函数对于哪些类型需要传参数,哪些需要传引用,除非模板库的使用者和开发者是同一个团队。即便可以知道,书写大量类型的特化显然是吃力不讨好的事。

问题总是要解决的,于是,一个最笨的方案被提出来了:完全可以写两套模板呀(提出这种方案的人大概忘了为什么要使用模板了吧)。典型的例子就是上篇博客中提到的tie函数,与他极为类似的有个make_tuple函数,下面是它们俩的实现:

  template<typename... _Elements>
    inline tuple<typename __strip_reference_wrapper<_Elements>::__type...>
    make_tuple(_Elements... __args)
    {
      typedef tuple<typename __strip_reference_wrapper<_Elements>::__type...>
        __result_type;
      return __result_type(__args...);
    }

  template<typename... _Elements>
    inline tuple<_Elements&...>
    tie(_Elements&... __args)
    {
      return tuple<_Elements&...>(__args...);
    }

make_tuple中多了__strip_reference_wrapper类,这其实主要是为了下面要提到的引用类的处理,对于普通的C++传值和传引用类型并没有什么效果,也就是说make_tuple提供了传值的接口,tie提供了传引用的接口。

不过我始终觉得写两套接口终究还是违背C++模板的初衷的,所以这样的设计或许更好一些:

class IsRef {};
template<typename... _Elements>
inline tr1::tuple<_Elements...>
make_tuple(_Elements... __args)
{
    return tr1::tuple<_Elements...>(__args...);
}

template<typename... _Elements>
inline tr1::tuple<_Elements&...>
make_tuple(IsRef isRef, _Elements&... __args)
{
    return tr1::tuple<_Elements&...>(__args...);
}

这样一来给人的感觉是一套接口了,但是那个多出的一个参数IsRef还是十分刺眼,仿佛相当于make_tuple2一样,似乎仍然是换汤不换药。更重要的是,大部分情况下需要部分参数传引用,部分传值,到目前为止都是一刀切的方案。于是,大神说了,谁挖的坑谁来填。改函数名和该参数数量这种重载方式都不够友好,最终还是模板提供了更有效的方法。

其实stl中的make_tuple就支持传引用和传值的参数。不过直接C++的形式还是不行的,得借助于它提供的一个包装类。用法如下:

int main()
{
    int a = 0;
    auto t1 = tr1::make_tuple(tr1::ref(a));
    get<0>(t1)++;
    cout << a << endl;
    return 0;
}

上面的程序输出结果为:1.

这里的tr1::ref就是stl中对引用进行包装的函数。它的返回值是reference_wrapper类,模板正是通过这一类型来判断参数是引用还是值,从而采取不同的操作。

  template<typename _Tp>
    inline reference_wrapper<_Tp>
    ref(_Tp& __t)
    { return reference_wrapper<_Tp>(__t); }
reference_wrapper的实现如下:
  /// reference_wrapper
  template<typename _Tp>
    class reference_wrapper
    : public _Reference_wrapper_base<typename remove_cv<_Tp>::type>
    {
      _Tp* _M_data;
    public:
      typedef _Tp type;

      explicit
      reference_wrapper(_Tp& __indata)
      : _M_data(std::__addressof(__indata))
      { }

      reference_wrapper(const reference_wrapper<_Tp>& __inref):
      _M_data(__inref._M_data)
      { }

      reference_wrapper&
      operator=(const reference_wrapper<_Tp>& __inref)
      {
        _M_data = __inref._M_data;
        return *this;
      }

      operator _Tp&() const
      { return this->get(); }

      _Tp&
      get() const
      { return *_M_data; }
    };
它的基类是用于支持各类函数指针的。并且上面的实现中已经删去了函数指针有关的实现。这个类只有一个成员变量,保存了被引用的变量的指针。定义了get方法用于得到引用值。即ref本质上传递的是对象的指针,但是包装类使其对外的接口与引用无异。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用Apache POI来实现根据模板填写Word的功能,具体步骤如下: 1. 在pom.xml中添加Apache POI的依赖: ```xml <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.2</version> </dependency> ``` 2. 创建一个Word模板文件,包含需要填写的内容,例如:${name},${age}等。 3. 编写代码实现根据模板填写Word的功能。以下是一个简单的示例: ```java public void createWord() throws IOException { // 读取模板文件 FileInputStream fis = new FileInputStream("template.docx"); XWPFDocument document = new XWPFDocument(fis); // 获取模板中的所有段落 List<XWPFParagraph> paragraphs = document.getParagraphs(); for(XWPFParagraph paragraph : paragraphs) { // 获取段落中的所有文本 List<XWPFRun> runs = paragraph.getRuns(); for(XWPFRun run : runs) { // 替换需要填写的内容 String text = run.getText(0); if(text != null && text.contains("${name}")) { text = text.replace("${name}", "张三"); run.setText(text, 0); } else if(text != null && text.contains("${age}")) { text = text.replace("${age}", "20"); run.setText(text, 0); } } } // 保存文件 FileOutputStream fos = new FileOutputStream("result.docx"); document.write(fos); fos.close(); fis.close(); } ``` 在上面的示例中,首先读取模板文件,然后遍历模板中的所有段落和文本,将需要填写的内容替换成实际的值,最后保存为一个新的Word文件。 注意:如果模板文件中包含表格或图片等其他内容,需要根据具体情况进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值