如何用pre-c 0x(VS2008)实现“Variadic Template”?

我使用的是Visual Studio 2008,我想实现没有变量参数列表的字符串格式化函数.

如何用pre-c 0x(VS2008)实现“Variadic Template”?

有没有任何图书馆实现这样的提升?

还是另一种方式来实现呢?

这是我的示例代码.
(当然,由于我使用的是VS2008,所以无法遵守.)

bool VarPrint(std::ostringstream& out,const std::string& s) 
{
    std::string::size_type offset = 0;
    if((offset = s.find("%")) != std::string::npos)
    {
        if(!(offset != s.size() - 1 && s[offset + 1] == '%'))
        {
            ASSERT(!"Missing Arguments!");
            return false;
        }
    }
    out << s;
    return true;
}

template<typename T,typename... Args>
bool VarPrint(std::ostringstream& out,const std::string& s,const T& value,const Args&... args) 
{
    std::string::size_type prev_offset = 0;
    std::string::size_type curr_offset = 0;
    while((curr_offset = s.find("%",prev_offset)) != std::string::npos)
    {
        out << s.substr(prev_offset,curr_offset);
            if(!(curr_offset != s.size() - 1 && s[curr_offset + 1] == '%'))
        {
            out << value;
            if(curr_offset + 2 < s.length())
                return VarPrint(out,s.substr(curr_offset + 2),args...);                   return true;
        }

        prev_offset = curr_offset + 2;
        if(prev_offset >= s.length)
            break;
    }
    ASSERT(!"Extra Argument Provided!");
    return false;
}

解决方法

在C 03,你有不同的可能性:

>为0-N参数生成重载(例如使用Boost.Preprocessor)
>使用Cons-Lists(cons(1)(“some string”)(foo))
>使用对象并重载一些运算符(operator()),或者像运算符%(如Boost.Format))

一个选项是有点棘手,我觉得,因为并不是每个人都可以很容易的理解宏,所以我只会保留它的短期解决方案,如果你计划迁移到C 0x很快.

第三个选项可能会提供一个很好的自定义触摸(使用许多语言的%符号进行格式化),但这也意味着需要记住这个特定的“可变”功能如何每次都工作.

我的个人喜好是cons方法,因为它解决了这两个问题:

>定义只涉及模板,所以它比1更可读和维护.
您可以定义一次机器,然后可以将其重新用于任何“可变”功能(并且它们仍然是功能),因此它更加一致,并且可以节省您的工作

例如,这里是如何工作的:

这个例子包括

#include <cassert>
#include <iostream>
#include <string>

对于附加值的结果类型的帮助器(它可能会更有效的前置,但这意味着以相反的顺序传递参数是反直觉的):

template <typename T,typename Next> struct Cons;
struct ConsEmpty;

template <typename Cons,typename U>
struct cons_result;

template <typename U>
struct cons_result<ConsEmpty,U> {
  typedef Cons<U,ConsEmpty> type;
};

template <typename T,typename U>
struct cons_result<Cons<T,ConsEmpty>,U> {
  typedef Cons<T,Cons<U,ConsEmpty> > type;
};

template <typename T,typename Next,Next>,typename cons_result<Next,U>::type> type;
};

缺点模板本身,用一个魔术运算符()来附加值.请注意,它会创建一个不同类型的新项目:

template <typename T,typename Next>
struct Cons {
  Cons(T t,Next n): value(t),next(n) {}

  T value;
  Next next;

  template <typename U>
  typename cons_result<Cons,U>::type operator()(U u) {
    typedef typename cons_result<Cons,U>::type Result;
    return Result(value,next(u));
  }
};

struct ConsEmpty {
  template <typename U>
  Cons<U,ConsEmpty> operator()(U u) {
    return Cons<U,ConsEmpty>(u,ConsEmpty());
  }
};

template <typename T>
Cons<T,ConsEmpty> cons(T t) {
  return Cons<T,ConsEmpty>(t,ConsEmpty());
}

重读了VarPrint:

bool VarPrint(std::ostream& out,ConsEmpty) {
    std::string::size_type offset = 0;
    if((offset = s.find("%")) != std::string::npos) {
        if(offset == s.size() - 1 || s[offset + 1] != '%')  {
            assert(0 && "Missing Arguments!");
            return false;
        }
    }
    out << s;
    return true;
}

template<typename T,typename Next>
bool VarPrint(std::ostream& out,std::string const& s,Cons<T,Next> const& cons) 
{
    std::string::size_type prev_offset = 0,curr_offset = 0;
    while((curr_offset = s.find("%",prev_offset)) != std::string::npos) {
        out << s.substr(prev_offset,curr_offset);
        if(curr_offset == s.size() - 1 || s[curr_offset + 1] != '%') {
            out << cons.value;
            if(curr_offset + 2 < s.length())
                return VarPrint(out,cons.next);
            return true;
        }
        prev_offset = curr_offset + 2;
        if(prev_offset >= s.length())
            break;
    }
    assert(0 && "Extra Argument Provided!");
    return false;
}

和演示

int main() {
  VarPrint(std::cout,"integer %i\n",cons(1));
  VarPrint(std::cout,"mix of %i and %s\n",cons(2)("foo"));
}

您可以查看ideone输出

integer 1
mix of 2 and foo

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...