C++: How can i create a function that accepts concatenated strings as parameter?

对着背影说爱祢 提交于 2019-12-01 17:21:31

It's impossible to do with the exact syntax you asked for unless you resort to macros.

But if you don't mind replacing << with ,, then you can do following:

#include <iostream>
#include <string>
#include <sstream>

void log_impl(const std::string &str)
{
    std::cout << str;
}

template <typename ...P> void log(const P &... params)
{
    std::stringstream stream;

    (stream << ... << params);
    // If you don't have C++17, use following instead of the above line:
    // using dummy_array = int[];
    // dummy_array{(void(stream << params), 0)..., 0};

    log_impl(stream.str());
}

int main()
{
    log("1", 2, '3'); // prints 123
}

For trivial projects this is one of the few things I use a MACRO for. You can do something like this:

#define LOG(m) do{ std::cout << timestamp() << ": " << m << '\n'; }while(0)

// ...

LOG("error: [" << errno "] " << filename << " does not exist.");

Generally MACROS should be avoided but there is no other way to get precisely this with a standard function. So...

Note: The empty condition do{...}while(0) enables you to place the MACRO in places that a MACRO usually can't go if it contains multiple statements.

You could do it by defining a new operator<<. From vague memory, implementing functions with these three signatures will do the trick:

std::string operator<<(const char * a, const std::string & b);
std::string operator<<(const std::string & a, const char * b);
std::string operator<<(const std::string & a, const std::string & b);

Each of them has to concatenate its arguments and return a std::string.

Howeever, it feels wrong. Goes against the grain of C++. I suggest a more C++-ish solution, namely to make your logger into a class, and write operator<<() members for that class, so you can run

customLog << "My Integer i = " << i << "." << "\n";

One approach is a simple utility class that uses a standard stream in a templated member function:

class LogStream {
    public:
        template <class T> LogStream& operator << (const T& rhs) {
            stream << rhs;
            return *this;
        }

    private:
        std::stringstream stream;
};

The stream member doing all the work is then used in the destructor,

~LogStream() {
    std::cout << stream.str() << std::endl;
}

and you can create temporary objects for passing your arguments to be concatenated:

LogStream() << "anything with std::ostream operator: " << 1.2345 << ' ' << std::hex << 12;

Additional state (e.g. a log level) can be passed to the constructor, often accompagnied by convenience functions like LogStream debug() { return LogStream(...); }. When you reach a certain point of sophistication though, you might want to switch to a logging library of course.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!