如何实现"可变参数模板"以pre-C ++ 0x中(VS2008)? [英] How to implement "Variadic Template" with pre-c++0x(VS2008)?

查看:105
本文介绍了如何实现"可变参数模板"以pre-C ++ 0x中(VS2008)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Visual Studio 2008中,我想实现字符串格式化功能的不变量参数列表

如何实现可变参数模板以pre-C ++ 0x中(VS2008)?

有一个实现此类似升压的图书馆吗?

或者另一种方式来实现这一点?

下面是我的示例code。
(当然,这不能因为我使用VS2008遵守。)

 布尔VarPrint(的std :: ostringstream&放大器;出来,常量标准::字符串&安培; S)
{
    标准::字符串:: size_type的偏移= 0;
    如果((偏移= s.find(%))!=标准::字符串::非营利组织)
    {
        如果(!(偏移量= s.size() - 1安培;&安培; S [偏移+ 1] =='%'))
        {
            ASSERT(缺少参数!!);
            返回false;
        }
    }
    出<< S;
    返回true;
}模板< typename的T,typename的参数... args>
布尔VarPrint(的std :: ostringstream&放大器;出来,常量标准::字符串&放大器; S,常量T&安培;价值,常量参数数量&安培; ...参数)
{
    标准::字符串:: size_type的prev_offset = 0;
    标准::字符串:: size_type的curr_offset = 0;
    而((curr_offset = s.find(%,prev_offset))!=标准::字符串::非营利组织)
    {
        出<< s.substr(prev_offset,curr_offset);
            如果(!(curr_offset = s.size() - 1安培;&安培; S [curr_offset + 1] =='%'))
        {
            出<<值;
            如果(curr_offset + 2'; s.length())
                返回VarPrint(出,s.substr(curr_offset + 2),ARGS ...);返回true;
        }        prev_offset = curr_offset + 2;
        如果(prev_offset> = s.length)
            打破;
    }
    ASSERT(额外的参数提供的!!);
    返回false;
}


解决方案

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


  1. 生成0-N参数重载(使用Boost。例如preprocessor)

  2. 使用禁忌列表(缺点(1)(一些字符串)(富)

  3. 使用对象和重载一些操作符(操作符()例如,或操作符%像Boost.Format库)

第一个选项是有点棘手,我的感觉,因为不是每个人都可以很容易地理解宏,所以我只会保留它的短项解决方案,如果你打算迁移到的C ++ 0x很快。

第三个选项可能会提供一个很好的定制触摸(格式化在许多语言中的符号做),但它也意味着一个人需要记得这个特殊的可变参数功能,每次工作。

我个人的preference是劣势的方法,因为它解决了两个问题:


  • 定义只涉及模板,所以它比1更好的可读性和maintanable。

  • 您定义的利弊,机械一次,你可以重新使用它的任何可变参数功能(和它们的仍然的功能),所以它是比较一致的,并保存你的工作

例如,这里是如何可以工作:

在包括本例中将使用:

 的#include<&了cassert GT;
#包括LT&;&iostream的GT;
#包括LT&;串GT;

一个的结果类型附加价值的帮手(也可能是与prepending更有效率,但是这意味着传入这是反直觉相反的顺序参数):

 模板< typename的T,typename的下一个>结构缺点;
结构ConsEmpty;模板< typename的缺点,typename的U>
结构cons_result;模板< typename的U>
结构cons_result< ConsEmpty,U> {
  缺点的typedef LT&; U,ConsEmpty>类型;
};模板< typename的T,typename的U>
结构cons_result<缺点< T,ConsEmpty>中U> {
  缺点的typedef LT&; T,缺点< U,ConsEmpty> >类型;
};模板< typename的T,typename的下一步,typename的U>
结构cons_result<缺点< T,下一步>中U> {
  缺点的typedef LT&; T,类型名cons_result<接下来,U> ::类型>类型;
};

缺点模板本身,附魔运算符()附加价值。需要注意的是它与不同类型创建一个新的项:

 模板< typename的T,typename的下一个>
结构缺点{
  缺点(T T,接下来N):值(T),下一个(N){}  的T值;
  下一页next;  模板< typename的U>
  类型名cons_result<缺点,U> ::类型运算符()(U U){
    的typedef typename的cons_result<缺点,U> ::类型结果;
    返回结果(值,接下来的(U));
  }
};结构ConsEmpty {
  模板< typename的U>
  缺点< U,ConsEmpty>运算符()(U U){
    返回缺点< U,ConsEmpty>(U,ConsEmpty());
  }
};模板< typename的T>
缺点< T,ConsEmpty>缺点(T(T)){
  返回缺点< T,ConsEmpty&GT(T,ConsEmpty());
}

一个再访 VarPrint 吧:

 布尔VarPrint(的std :: ostream的和放大器;出来,常量标准::字符串&放大器; S,ConsEmpty){
    标准::字符串:: size_type的偏移= 0;
    如果((偏移= s.find(%))!=标准::字符串::非营利组织){
        如果(偏移== s.size() - 1 || S [偏移+ 1] ='%'!){
            断言(0安培;&安培;缺少参数!);
            返回false;
        }
    }
    出<< S;
    返回true;
}模板< typename的T,typename的下一个>
布尔VarPrint(的std :: ostream的和放大器;出来,
              标准::字符串常量和放大器; S,
              缺点< T,下一个>常量和放大器;缺点)
{
    标准::字符串:: size_type的prev_offset = 0,curr_offset = 0;
    而((curr_offset = s.find(%,prev_offset))!=标准::字符串::非营利组织){
        出<< s.substr(prev_offset,curr_offset);
        如果(curr_offset == s.size() - 1 || S [curr_offset + 1] ='%'){
            出<< cons.value;
            如果(curr_offset + 2'; s.length())
                返回VarPrint(出,s.substr(curr_offset + 2),cons.next);
            返回true;
        }
        prev_offset = curr_offset + 2;
        如果(prev_offset> = s.length())
            打破;
    }
    断言(0安培;&安培;额外的参数提供的!);
    返回false;
}

和演示

  INT的main(){
  VarPrint(标准::法院,整数%I \\ N,缺点(1));
  VarPrint(标准::法院的搭配%i和%S \\ N,缺点(2)(富));
}

您可以检查输出 ideone

  1的整数
2与富混

I'm using Visual Studio 2008, and I want to implement string formatting function without Variable Argument List.

How to implement "Variadic Template" with pre-c++0x(VS2008)?

Is there any library which implements this like boost?

Or another way to implement this?

Here is my sample code. (of course, this can't be complied because i'm using 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;
}

解决方案

In C++03, you have different possibilities:

  1. generate overloads for 0-N arguments (using Boost.Preprocessor for example)
  2. use Cons-Lists (cons(1)("some string")(foo))
  3. use object and overload some operator (operator() for example, or operator% like Boost.Format)

The first option is a bit tricky, I feel, because not everyone can understand macros easily, so I would only reserve it for short-terms solutions if you plan on migrating to C++0x soon.

The third option may provide a nice custom touch (formatting is done with a % sign in many languages), but it also means that one needs to remember how this particular "variadic" function works each time.

My personal preference is the cons approach because it solves both issues:

  • the definition involves only templates, so it is more readable and maintanable than 1.
  • you define the cons-machinery once, and you can then re-use it for any "variadic" function (and they remain functions), so it is more consistent, and saves you work

For example, here is how it could work:

The includes that this example will use:

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

A helper for the result type of appending a value (it could be more efficient with prepending, but that would mean passing the arguments in reverse order which is counter-intuitive):

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, typename U>
struct cons_result<Cons<T, Next>, U> {
  typedef Cons<T, typename cons_result<Next, U>::type> type;
};

The Cons template itself, with a magic operator() to append value. Note that it creates a new item with a different 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());
}

A revisited VarPrint with it:

bool VarPrint(std::ostream& out, const std::string& s, 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, s.substr(curr_offset + 2), cons.next);
            return true;
        }
        prev_offset = curr_offset + 2;
        if(prev_offset >= s.length())
            break;
    }
    assert(0 && "Extra Argument Provided!");
    return false;
}

And the demo

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

You can check the output on ideone:

integer 1
mix of 2 and foo

这篇关于如何实现&QUOT;可变参数模板&QUOT;以pre-C ++ 0x中(VS2008)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆