我经常写这样的类:

    Logger::Logger(bool log_time_, bool log_percentage, bool log_size):log_time(log_time_)... //made up example

    Logger::Log()
    {
        string log_line;
        if (log_time)
            log_line+=(get_time());
        if (log_percentage)
            log_line+=(get_percentage());
        //...
    }

而且我想知道是否有一种方法可以将使用模板魔术的类转换为在编译时执行“if(something)”部分的代码。

编辑:
bool变量的值在编译时是已知的。

最佳答案

前言
在本文中可以找到两种解决方案,一种使用C++ 03,另一种使用C++ 11。
如果您想要一个真正的编译时间,那么这很难(即,您需要编写大量代码),如果保证永远不会有任何运行时开销(没有函数跳转等)。
但是有可能,尽管如果您想为其添加其他选项(在C++ 03中),则代码将非常繁琐。我建议您查看以下解决方案。

C++ 03中的解决方案
您的编译器应该足够聪明,可以优化对LogHelper<+NONE>的任何调用,尽管如果您只是在寻找更具可读性的代码,而不是获得出色的性能,则此语法非常不错。

enum LoggerType {
  NONE    =0,
  DATE    = (1<<0),
  TIME    = (1<<1),
  PERCENT = (1<<2)
};

template<int>     void LogHelper (std::string&);

template<> inline void LogHelper<+NONE>    (std::string&)   {}
template<> inline void LogHelper<+DATE>    (std::string& s) {s += "1970-01-01 ";}
template<> inline void LogHelper<+TIME>    (std::string& s) {s += "12:01:01 ";}
template<> inline void LogHelper<+PERCENT> (std::string& s) {s += "42% ";}

template<int LOG_FLAG = NONE>
struct Logger {
  static void log (std::string const& description) {
    std::string s1;

    LogHelper<DATE    & LOG_FLAG> (s1);
    LogHelper<TIME    & LOG_FLAG> (s1);
    LogHelper<PERCENT & LOG_FLAG> (s1);

    std::cerr.width (25);
    std::cerr << s1 << " >> " << description << std::endl;
  }
};
...
int
main (int argc, char * argv[]) {
  Logger<DATE|TIME|PERCENT> foo_log;
  Logger<TIME>             time_log;
  Logger<>                   no_log;

  time_log.log ("log objects initialized!");
  foo_log .log ("using foo_log");
  no_log  .log ("about to terminate application");
}
输出
                12:01:01  >> log objects initialized!
 1970-01-01 12:01:01 42%  >> using foo_log
                          >> about to terminate application

使用可变参数模板的解决方案(C++ 11)
enum LoggerType {
  NONE, PERCENT, DATE, TIME
};

template<LoggerType T = NONE, LoggerType ... Next>
std::string LogHelper () {
  return LogHelper<T> () + "; " + LogHelper<Next...> ();
}

template<> std::string LogHelper<NONE>    () {return ""; }
template<> std::string LogHelper<DATE>    () {return "1970-01-01";}
template<> std::string LogHelper<TIME>    () {return "00:01:42";}
template<> std::string LogHelper<PERCENT> () {return "42%";}

template<LoggerType ... Types>
struct Logger {
  static void log (std::string const& description) {
    std::cerr.width (25);
    std::cerr << LogHelper<Types...> ();
    std::cerr << " >> "  <<   description;
    std::cerr << std::endl;
  }
};
...
int
main (int argc, char * argv[]) {
  Logger<DATE,TIME,PERCENT> foo_log;
  Logger<TIME>             time_log;
  Logger<>                   no_log;

  time_log.log ("log objects initialized!");
  foo_log .log ("using foo_log");
  no_log  .log ("about to terminate application");
}
输出
                 00:01:42 >> log objects initialized!
1970-01-01; 00:01:42; 42% >> using foo_log
                          >> about to terminate application

09-10 05:25
查看更多