C++ 是否可以使用模板元编程对类将执行的功能进行编译时选择?
我经常这样写课程:C++ 是否可以使用模板元编程对类将执行的功能进行编译时选择?,c++,templates,C++,Templates,我经常这样写课程: 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_perc
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());
//...
}
template <bool Opt1, bool Opt2> void foo()
{
Action1<Opt1>();
Action2<Opt2>();
}
template <bool> void Action1();
template <bool> void Action2();
template <> void Action1<true>() { /* ... */ }
template <> void Action1<false>() { /* ... */ }
template <> void Action2<true>() { /* ... */ }
template <> void Action2<false>() { /* ... */ }
我想知道有没有办法将使用模板魔术的类转换成在编译时执行“if(something)”部分的代码
编辑:
bool变量的值在编译时是已知的。是的,这是可能的,尽管有些编译器不喜欢它。但是,您最终将得到一组不同的类,因为您必须提供布尔值作为模板说明符(可能不是正确的术语)
我想你最好还是用虚拟日志的方法来代替?然后创建几个类,每个类定义自己的日志方法。除非您有其他原因,否则我建议在这种情况下使用虚拟函数而不是模板。是的,这是可能的,尽管有些编译器不喜欢您使用虚拟函数。但是,您最终将得到一组不同的类,因为您必须提供布尔值作为模板说明符(可能不是正确的术语)
我想你最好还是用虚拟日志的方法来代替?然后创建几个类,每个类定义自己的日志方法。除非您有其他原因,否则我建议在这种情况下使用虚拟函数而不是模板。当然。大概是这样的:
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());
//...
}
template <bool Opt1, bool Opt2> void foo()
{
Action1<Opt1>();
Action2<Opt2>();
}
template <bool> void Action1();
template <bool> void Action2();
template <> void Action1<true>() { /* ... */ }
template <> void Action1<false>() { /* ... */ }
template <> void Action2<true>() { /* ... */ }
template <> void Action2<false>() { /* ... */ }
模板void foo()
{
行动1();
行动2();
}
模板void Action1();
模板void Action2();
模板void Action1(){/*…*/}
模板void Action1(){/*…*/}
模板void Action2(){/*…*/}
模板void Action2(){/*…*/}
像调用
foo()一样调用这个函数代码>当然可以。大概是这样的:
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());
//...
}
template <bool Opt1, bool Opt2> void foo()
{
Action1<Opt1>();
Action2<Opt2>();
}
template <bool> void Action1();
template <bool> void Action2();
template <> void Action1<true>() { /* ... */ }
template <> void Action1<false>() { /* ... */ }
template <> void Action2<true>() { /* ... */ }
template <> void Action2<false>() { /* ... */ }
模板void foo()
{
行动1();
行动2();
}
模板void Action1();
模板void Action2();
模板void Action1(){/*…*/}
模板void Action1(){/*…*/}
模板void Action2(){/*…*/}
模板void Action2(){/*…*/}
像调用foo()一样调用这个函数代码>是对于编译时常量,您可以使用模板
编程:
template<bool log_time, bool log_perchentage, bool log_size>
struct Logger
{
static void log()
{ // log everything
string log_line;
log_line+=(get_time());
log_line+=(get_perchentage());
log_line+=(get_size());
}
};
template<>
struct Logger<false, false, false>
{
static void log()
{ // nothing to log
}
};
模板
结构记录器
{
静态无效日志()
{//记录一切
字符串日志行;
log_line+=(get_time());
log_line+=(get_percentage());
log_line+=(get_size());
}
};
样板
结构记录器
{
静态无效日志()
{//没有要记录的内容
}
};
您还可以将中间版本专门化为Logger
和Logger
等。另一种避免几种专门化的方法是将时间/百分比/大小
分为不同的结构
并分别记录它们。是对于编译时常量,您可以使用模板
编程:
template<bool log_time, bool log_perchentage, bool log_size>
struct Logger
{
static void log()
{ // log everything
string log_line;
log_line+=(get_time());
log_line+=(get_perchentage());
log_line+=(get_size());
}
};
template<>
struct Logger<false, false, false>
{
static void log()
{ // nothing to log
}
};
模板
结构记录器
{
静态无效日志()
{//记录一切
字符串日志行;
log_line+=(get_time());
log_line+=(get_percentage());
log_line+=(get_size());
}
};
样板
结构记录器
{
静态无效日志()
{//没有要记录的内容
}
};
您还可以将中间版本专门化为Logger
和Logger
等。另一种避免多个专门化的方法是将time/percentage/size
分为不同的struct
并分别记录它们。您可以这样做
struct DummyEnhancer
{
void operator()(string& s) const{
}
};
struct TimerEnhancer
{
void operator()(string& s) const{
s += "time";
}
};
struct PercenterEnhancer
{
void operator()(string& s) const{
s += "percent";
}
};
template <typename Timer , typename Percenter>
struct Logger
{
void Log()
{
string log_line;
Timer t;
t( log_line );
Percenter p;
p( log_line );
}
};
int main()
{
Logger<DummyEnhancer,DummyEnhancer> foo;
foo.Log();
Logger< TimerEnhancer , PercenterEnhancer > bar;
bar.Log();
return 0;
}
struct dummeyenhancer
{
void运算符()(字符串和s)常量{
}
};
结构TimerEnhancer
{
void运算符()(字符串和s)常量{
s+=“时间”;
}
};
结构百分比增强器
{
void运算符()(字符串和s)常量{
s+=“百分比”;
}
};
样板
结构记录器
{
无效日志()
{
字符串日志行;
定时器t;
t(对数线);
百分比p;
p(对数线);
}
};
int main()
{
傅先生;
foo.Log();
记录器bar;
bar.Log();
返回0;
}
foo.Log()
struct DummyEnhancer
{
void operator()(string& s) const{
}
};
struct TimerEnhancer
{
void operator()(string& s) const{
s += "time";
}
};
struct PercenterEnhancer
{
void operator()(string& s) const{
s += "percent";
}
};
template <typename Timer , typename Percenter>
struct Logger
{
void Log()
{
string log_line;
Timer t;
t( log_line );
Percenter p;
p( log_line );
}
};
int main()
{
Logger<DummyEnhancer,DummyEnhancer> foo;
foo.Log();
Logger< TimerEnhancer , PercenterEnhancer > bar;
bar.Log();
return 0;
}
struct dummeyenhancer
{
void运算符()(字符串和s)常量{
}
};
结构TimerEnhancer
{
void运算符()(字符串和s)常量{
s+=“时间”;
}
};
结构百分比增强器
{
void运算符()(字符串和s)常量{
s+=“百分比”;
}
};
样板
结构记录器
{
无效日志()
{
字符串日志行;
定时器t;
t(对数线);
百分比p;
p(对数线);
}
};
int main()
{
傅先生;
foo.Log();
记录器bar;
bar.Log();
返回0;
}
foo.Log()
本文将提供两种解决方案,一种使用C++03,另一种使用C++11
如果你想要一个真正的编译时间(如果保证的话)没有任何运行时开销(没有函数跳转等),那就很难(即,你需要编写很多代码)
然而,这是可能的,尽管如果您想在代码中添加另一个选项(在C++03中),那么代码的维护将非常繁琐。我建议您查看以下解决方案
C++03中的解决方案
您的编译器应该足够聪明,可以优化掉对LogHelper
的任何调用,不过如果您只是寻找可读性更强的代码,而不是获得优异的性能,那么这种语法是非常好的
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;
}
};
使用可变模板的解决方案(C++11)
前言
本文将提供两种解决方案,一种使用C++03,另一种使用C++11
如果你想要一个真正的编译时间(如果保证的话)没有任何运行时开销(没有函数跳转等),那就很难(即,你需要编写很多代码)
然而,这是可能的,尽管如果您愿意,代码的维护将非常繁琐