2017-08-11 61 views
4

我有我的应用程序的不同部分调用记录器功能来记录详细信息。C++连接不同类型为函数的字符串

Logger类

std::string filename = "blahblah"; // variable to store the location of the properties file 
log4cpp::PropertyConfigurator::configure(filename); 

void Logger::logging(const std::string& msg) 
{ 
    Log4cpp::Category& myLogger = log4cpp::Category::getRoot(); 

    myLogger.log(log4cpp::Priority::INFO, msg);//only takes in string as input 
} 

调用类

Logger logMe; 

int a = 5; 
double b = 6; 

logMe.logging("log this msg" + a + "," + b); 

我意识到,上面给我的错误,因为ab是不同类型的。解决这个问题的方法之一是使用std::to_string

logMe.logging("log this msg" + std::to_string(a) + "," + std::to_string(b)); 

不过,我有上百个电话到日志功能,这将是耗时每个调用编辑到std::to_string。是否有更简单的方法可以做到这一点?

呵呵并且为了澄清,代码之前的工作方式是通过定义#define函数。

#Define logging(FLAG, X)\ 
do {\ 
    ... 
    clog << x; \ 
}while(0) 

logging(LogFlag::Warning, "log this msg" << a << "," << b << endl); 

但我现在正在重写部分代码以符合静态测试。

在此先感谢。

+2

应该以标准库为例 - 实现'operator <<'。 – LogicStuff

回答

4

您可以添加的logging,需要一个参数组,并加入它转换成字符串超载,使用std::stringstream

在C++ 17中,我们可以用一个fold expression,例如

template <typename Args ...> 
void Logger::logging(Args ... args) 
{ 
    std::stringstream ss; 
    (ss << ... << args); 

    Log4cpp::Category& myLogger = log4cpp::Category::getRoot(); 

    myLogger.log(log4cpp::Priority::INFO, ss.str()); 
} 

在C++ 11或14中,我们必须slightly more tricky

template <typename ... Args > 
void Logger::logging(Args ... args) 
{ 
    std::stringstream ss; 
    std::initializer_list<int> unused{ (ss << args, 0)... }; 

    Log4cpp::Category& myLogger = log4cpp::Category::getRoot(); 

    myLogger.log(log4cpp::Priority::INFO, ss.str()); 
} 

然后调用或者作为例如

logMe.logging("log this msg", a, ",", b); 
+0

我试过使用这种方法,但我得到“无效的操作数类型'const unsigned int'到二进制'operator <<'。该方法只适用于int,因为std :: initializer_list ? –

+0

@TonyTony你怎么称呼它?它应该是'logMe.logging(“log this msg”,a,“,”,b);' – Caleth

3

这很容易使用stringstream。您可以使用str()将其转换为std::string

#include <sstream> 
... 
int a = 5; 
double b = 6; 

std::stringstream ss; 
ss << "log this msg" << a << b; 
std::cout << ss.str() << std::endl; 
logMe.logging(ss.str()); 
+0

我知道我可以使用stringstream,但是我仍然必须将std :: stringstream代码添加到调用logMe.logging的每一行。所以如果我有500个电话,我必须添加std :: stringstream代码500次。因此,我问是否有更简单的方法。但谢谢你的回答! –

+0

@TonyTony我不确定除了覆盖操作员之外是否有更简洁的方法。但是,我认为需要更改很多代码?即无论您在哪里进行日志调用。 – iyop45

+0

对运营商来说,似乎是迄今为止最好的解决方案。但是,如果说我想添加另一个参数来指定日志标志,问题就会出现。 (例如,logMe。日志记录(Flag :: Warning,“log this msg”); –

4

我建议增加一个operator<<()到类

class Logger 
{ 
    public: 

      Logger &operator<<(const std::string &s) 
      { 
       logging(s) 
       return *this; 
      }; 

      Logger &operator<<(const char *s) 
      { 
       return operator<<(std::string(s)); 
      } 


      template <class T> 
       Logger &operator<<(const T &v) 
      { 
       std::ostringstream s; 
       s << v; 
       return operator<<(logging(ss.str())); 
      }; 

     // other stuff you have in your class, including the logging() function 
}; 

// to use 

logMe << "log this msg" << a << b; 

不太如你所描述使用此相同的语法,但它的作品更普遍。