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

后端 未结 2 1760
慢半拍i
慢半拍i 2020-12-09 05:51

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

How to implement \"Variadic Templa

2条回答
  •  [愿得一人]
    2020-12-09 06:22

    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 
    #include 
    #include 
    

    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  struct Cons;
    struct ConsEmpty;
    
    template 
    struct cons_result;
    
    template 
    struct cons_result {
      typedef Cons type;
    };
    
    template 
    struct cons_result, U> {
      typedef Cons > type;
    };
    
    template 
    struct cons_result, U> {
      typedef Cons::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 
    struct Cons {
      Cons(T t, Next n): value(t), next(n) {}
    
      T value;
      Next next;
    
      template 
      typename cons_result::type operator()(U u) {
        typedef typename cons_result::type Result;
        return Result(value, next(u));
      }
    };
    
    struct ConsEmpty {
      template 
      Cons operator()(U u) {
        return Cons(u, ConsEmpty());
      }
    };
    
    template 
    Cons cons(T t) {
      return Cons(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
    bool VarPrint(std::ostream& out,
                  std::string const& s,
                  Cons 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"));
    }
    

    Output:

    integer 1
    mix of 2 and foo
    

提交回复
热议问题