Блог пользователя alvin777

Автор alvin777, 10 лет назад, По-русски

Игрался с C++11 variadic templates, получилось вывести для PR(a, b, s) строку вида "a: 10, b: 5.1, s: asd".

#define PR(...) pr(#__VA_ARGS__, __VA_ARGS__);

template<typename T>
void pr(const string& name, T t) {
    cout << name << ": " << t << endl;
}

template<typename T, typename ... Types>
void pr(const string& names, T t, Types ... rest) {
    auto comma_pos = names.find(',');
    cout << names.substr(0, comma_pos) << ": " << t << ", ";
    
    auto next_name_pos = names.find_first_not_of(" \t\n", comma_pos + 1);
    pr(string(names, next_name_pos), rest ...);
}

int a = 3;
float b = 5.1;
string s = "asd";

PR(a, b, s);
  • Проголосовать: нравится
  • +67
  • Проголосовать: не нравится

»
10 лет назад, # |
Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

Есть мнение, что нафиг такое никому в шаблоне не надо)

Во-первых, довольно мусорно выглядит даже по сравнению с другими вещами, которые можно в решениях встретить (а если по памяти придется писать?). Проще все-таки вот так.

void out() { cout << '\n'; }
template <typename T, typename... Args>
void out(const T& value, const Args&... args)
{ cout << value; out(args...); }
#define dbg(x) #x" = ", x, "; "

// example of usage:
out(dbg(a), dbg(b), "that's what I'm talking about!");

Во-вторых, под MS C++ без проблем пока нигде не зашлешь такое (когда g++ решит дать TL) — variadic templates только в комплекте 2013 года есть (и в дополнении к 2012 вроде).

  • »
    »
    10 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    out(dbg(a), dbg(b), "that's what I'm talking about!");
    

    Лучше уж так не извращаться, обычный cerr удобнее по-моему.

    • »
      »
      »
      10 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      С некоторой натяжкой можно утверждать, что это вообще применимо только для отладочного вывода printf/scanf — юзеров (им привычнее через запятую). Для них cerr не катит. Также замечу, что и cin/cout — юзерам cerr не катит, т.к. эти вызовы все равно удалять придется перед тем как засылать (вывод жрет время).

      У меня в коде вообще вот такая вещь.


      struct debug_t { template <typename T> debug_t& operator<<(const T& value) { # ifdef VERBOSE cout << value; # endif return *this; } } debug;

      Если взять этот "поток" debug, то вполне можно включить в код любителей printf/scanf с тем, что я указал выше.

»
10 лет назад, # |
Rev. 2   Проголосовать: нравится +7 Проголосовать: не нравится

С помощью макросов подобную штуку можно реализовать для любого компилятора и стандарта C++. Там только количество параметров будет ограничено, но это не критично, ибо больше 5-6 вряд ли понадобится. http://ideone.com/y39aaF

»
10 лет назад, # |
Rev. 3   Проголосовать: нравится +17 Проголосовать: не нравится

It's really cool. Since, it's shorter to write, I also like using operator, function like operator<< function of std::ostream class with a variadic macro, but without a variadic template.

#include <iostream>
#include <string>
#define PR(a...)    do { std::cout << #a << ": "; pr,a; std::cout << '\n'; } while (false)

struct print {
    template <typename T>  
    print& operator,(const T& v) {
        std::cout << v << ", ";
        return *this;
    }
} pr;

int main()
{
    int a = 3;
    float b = 5.1;
    std::string s = "asd";

    PR(a, b, s);
}

a, b, s: 3, 5.1, asd,