C ++ Vector wrapper around a variational function

I have an api that looks like this:

template<typename... Args>
Widget::Widget(std::string format_str, Args&&... args);

What would you call this method if you have a row vector for 'args', i.e. argument length unknown at compile time?

What would an implementation of a wrapper function look like, which converts it into something similar?

template<typename... Args>
Widget::WrapperWidget(std::string format_str, vector<string>);
+4
source share
3 answers

The following may help:

#if 1 // Not in C++11
#include <cstdint>

template <std::size_t ...> struct index_sequence {};

template <std::size_t I, std::size_t ...Is>
struct make_index_sequence : make_index_sequence < I - 1, I - 1, Is... > {};

template <std::size_t ... Is>
struct make_index_sequence<0, Is...> : index_sequence<Is...> {};

#endif // make_index_sequence

// you may use `std::tostring`
template <typename T> std::string myToString(T&& t);

class Widget
{
public:
    Widget(std::string format_str, const std::vector<std::string>& v);

    // this will call Widget(std::string, const std::vector<std::string>&)
    template<typename... Args>
    explicit Widget(std::string format_str, Args&&... args) :
        Widget(format_str, std::vector<std::string>{myToString(std::forward<Args>(args))...})
    {}


    // This will call Widget(format_str, a[0], a[1], .., a[N - 1]) // So the Args&&... version
    template <std::size_t N>
    Widget(std::string format_str, const std::array<std::string, N>& a) :
        Widget(format_str, a, make_index_sequence<N>())
    {}

private:
    template <std::size_t N, std::size_t...Is>
    Widget(std::string format_str, const std::array<std::string, N>& a, const index_sequence<Is...>&) :
        Widget(format_str, a[Is]...)
    {}

};
0
source

The function Widget::Widgetdoes not actually exist, it is only a template. A function is created only after specifying the number and types of parameters. This should be done at compile time.

Since vector length is only available at runtime, I can only think of this solution:

switch (v.size())
{
    case 0: f(fmt); break;
    case 1: f(fmt, v[0]); break;
    case 2: f(fmt, v[0], v[1]); break;
    case 3: f(fmt, v[0], v[1], v[2]); break;
    //... etc
}

, f .

, .

, , , . , .

, . :

string s = format_vector_runtime(fmt, v);
f("%s", s);

f - , , , " " - Widget.

+5

. , , -. Variadic class-templates. :

#include <vector>
#include <string>
#include <iostream>
#include <exception>

using StrCIter = std::string::const_iterator;

void printerHelper(StrCIter& fmtPos, StrCIter fmtEnd, std::vector<std::string>& vec)
{
  // if the vector is empty, we simply return without doing anything
  // and instead print the next argument
  auto vecIter = vec.begin ();

  while(vecIter != vec.end () && fmtPos != fmtEnd)
  {
    if(*fmtPos == '%' && *(fmtPos + 1) == 's')
    {
      std::cout << *vecIter++;
      fmtPos += 2;
      continue;
    }

    std::cout << *fmtPos++;
  }
}

template <typename T>
void printerHelper(StrCIter& fmtPos, StrCIter fmtEnd, const T& value)
{
  std::cout << value;
  fmtPos += 2;
}

void myPrintfHelper(StrCIter pos, StrCIter end)
{
  // end of expansion - no more format arguments, just print remaining characters
  while(pos != end)
  {
    if(*pos == '%')
    {
      throw "More format specifiers than arguments provided!";
    }

    std::cout << *pos++;
  }
}

template <typename Head, typename ... Tail>
void myPrintfHelper(StrCIter pos, StrCIter end, Head&& head, Tail&&... tail)
{
  while(pos != end)
  {
    if(*pos == '%' && *(pos + 1) == 's')
    {
      printerHelper (pos, end, head);
      return myPrintfHelper(pos, end, std::forward<Tail>(tail)...);
    }

    std::cout << *pos++;
  }
}

template <typename ... Args>
void myPrintf(const std::string& format, Args&& ... args)
{
  myPrintfHelper (format.begin(), format.end (), std::forward<Args>(args)...);
}

int main()
{
  std::vector<std::string> v = {"world", "magic"};
  myPrintf("Hello, %s! Welcome to the %s of variadic template %s! This ... is ... C++%s!", "StackOverflow", v, 11);
  return 0;
}

, formate, ( %s), , . , ,

printf(), , , .

, ​​ Stroustrups printf - std::string string const char*.

, , printHelper, , operator<<(std::ostream&[, ...]), .

All the overload that needs to be done is to adjust the format string iterator setting and print the material when the format specifier is hit. In my two examples, I am doing this ahead of 1 to determine that we are in the format specifier, but there are other ways.

By the way, the conclusion:

Hi StackOverflow! Welcome to the world of variable magic! This ... is ... C ++ 11!

+1
source

Source: https://habr.com/ru/post/1523498/


All Articles