skip to Main Content

I use this define in c++ to debug my variables it works in clion and codeblocks but does not work in visual studio 22.

Error C2010 ‘.’: unexpected in macro parameter list codeforces

the file name is "codeforces"

#define error(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }
void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {
    cerr << *it << " = " << a << endl;
    err(++it, args...);
}

I use this code below instead but it’s not functional if there is alot of variables since i’ll need to copy-paste is alot

#define error(s) cout << #s << " = " << s << endl;

How can I fix this problem ?

2

Answers


  1. The correct preprocessor syntax would be ... for the parameter and #__VA_ARGS__ for its expansion:

    #define error(...)                               
        {                                            
            string _s = #__VA_ARGS__;                
            replace(_s.begin(), _s.end(), ',', ' '); 
            stringstream _ss(_s);                    
            istream_iterator<string> _it(_ss);       
            err(_it, __VA_ARGS__);                   
        }
    

    Another, not so macro intense, version could be to pass on the stringified #__VA_ARGS__ to a C++ function template. I made a pre- C++20 and a C++20 version for that here and here’s the C++20 demo.

    Login or Signup to reply.
  2. As others have pointed out, args... is not standard C++. To capture everything in the parentheses of a macro, simply use ... and then refer to it through __VA_ARGS__.
    See GCC Variadic Macros, and cppreference: Replacing text macros.

    Besides that, you should also minimize the use of macros as much as possible.

    #define error(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }
    

    You only need the macro so that you can call do_error and give it the string representation of the passed expression at the same time.
    The rest can just be a variadic function template:

    template <typename... Args>
    void do_error(string_view text, const Args&... args) {
        string s = text;
        // TODO: this code is very naive and not safe against commas
        //       within string literals or parentheses
        replace(s.begin(), s.end(), ',', ' ');
        stringstream _ss(_s);
        istream_iterator<string> it(ss);
        err(it, args...);
    }
    
    // note: __VA_OPT__ (C++20) is needed to handle empty lists correctly.
    //       There exist less elegant workarounds, e.g. you could set up
    //       do_error()'s returned type to give you the syntax:
    //         do_error(#__VA_ARGS__)(__VA_ARGS__)
    #define error(...) do_error(#__VA_ARGS__ __VA_OPT__(,) __VA_ARGS__)
    

    Also note that your err function template can be improved:

    template<typename... Args>
    void err(istream_iterator<string> it, const Args&... args) {
        // fold expression (C++17)
        ((cerr << *it << " = " << args << endl), ...);
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search