Variadic-функция, которая принимает строки и целые числа, форматировать последние и объединять все? - PullRequest
0 голосов
/ 28 января 2019

Я пытаюсь использовать ответ от DanielKO в этом вопросе для своих нужд, но я не знаком с шаблонами и функциями variadic, и я не понимаю, что мне делать.

Мне нужна переменная функция c ++ (11), которую я могу вызвать следующим образом:

 String NewMsg = CreateMessage("SET",16,1,17,0,"RED",47);

и иметь NewMsg = "SET, 0010,0001,0011,0000, RED,002F ".

Я даже не могу получить, где я должен добавить запятую между аргументами.А потом: Как я могу различать целые числа и строки при разборе аргументов, чтобы отформатировать каждое целое число в шестнадцатеричные строки?

Ответы [ 3 ]

0 голосов
/ 28 января 2019

Один из вариантов - использовать рекурсию с шаблонами, как это сделал Passer By в своем ответе.Однако, на мой взгляд, более элегантным решением (если вы можете использовать языковые функции C ++ 17) является использование сложенного выражения , чтобы избежать рекурсии.Выражение расширяется так, что Append вызывается непосредственно для каждого аргумента, что-то вроде цикла for для аргументов, вычисляемых во время компиляции.

template <class T>
void Append(std::ostringstream &out, T &&arg) {
    out << "," << std::forward<T>(arg);
}

template <class... TArgs>
std::string CreateMessage(TArgs &&...args) {
    std::ostringstream out;
    (Append(out, std::forward<TArgs>(args)), ...);
    return out.str().substr(1);
}

Демонстрационная версия здесь .

0 голосов
/ 28 января 2019

Смешивая два других решения (рекурсивное от Passer By и C ++ 17-кратное выражение от Ника Мёртина), вы можете написать CreateMessage() без рекурсии (в аналогичном-кратном выражении) также на C ++11

std::string const & getStr (std::string const & ret)

 { return ret; }

std::string getStr (int val)
 {
   std::ostringstream ret;

   ret << std::hex << std::setw(4) << std::setfill('0') << val;

   return ret.str();
 }

template <typename ... Ts>
std::string CreateMessage (Ts const & ... args)
 {
   using unused = int[];

   std::string ret   = "";
   std::string comma = "";

   (void)unused { 0, ( ret += comma + getStr(args), comma = ",", 0 )... };

   return ret;
 }

- РЕДАКТИРОВАТЬ -

ОП спрашивает

Не хотите ли вы научить меня, как этосложить "работает линия?Как мне «прочитать» это?

Ну ... строка следующая

(void)unused { 0, ( ret += comma + getStr(args), comma = ",", 0 )... };

, где unused - псевдоним (using) для int[].

В нем используется тот факт, что пакет переменных (аргументы шаблона или функции) может быть расширен в контексте инициализации массива в стиле C, а также используется мощность оператора запятой (свойство оператора запятой).из exec / compute и отбрасывать то, что слева от запятой).

Итак, у вас есть расширение (для каждого аргумента в args...)

( ret += comma + getStr(args), comma = ",", 0 )

где

1) вы добавляете comma + getStr(args) к ret, где comma пуст для первого аргумента и равно "," (см. (2)) для следующих аргументов

2) для первогооператор запятой отбрасывает значение ret и присваивает "," comma (таким образом, у вас есть пустые comma в первых ret += и "," для следующих ret +=

3)Второй оператор запятой отбрасывает значение запятой и возвращает 0 для инициализации unuses

Таким образом, ret увеличивается на All getStr(args) разделен "," и неиспользуемый массив инициализируется нулями.

Соблюдайте еще пару моментов:

a) в массиве (без имени unused)список инициализации, у вас есть начальный и не связанный с переменным ноль ({ 0,);это необходимо в случае, если список args... пуст, поэтому строка становится (void)unsed { 0 };, что допустимо, вместо (void)unused { }; (без этого нуля), что является синтаксической ошибкой

b) unused предшествует (void);это не является строго необходимым, но полезно, чтобы избежать предупреждения типа «объект определен, но не используется».

0 голосов
/ 28 января 2019

Вы используете рекурсию и перегрузку функций

std::string CreateMessage(int i)
{
    return /* i formatted as hex */;
}

std::string CreateMessage(const char* s)
{
    return s;
}

template<typename T, typename... Ts>
std::string CreateMessage(T t, Ts... ts)
{
    return CreateMessage(t) + "," + CreateMessage(ts...);
}
...