用于格式化的字符串参数与模板参数
String Argument vs. Template Parameter for Formatting
我想知道是否可以考虑使用这两种提供格式字符串的方法之一 "more correct"。显然两者都有效,但一个需要在命名空间中维护一系列常量字符串,而另一个使用 class:
#include <ctime>
#include <iostream>
// Method 1: constant strings:
char const* STANDARD = "%c";
char const* ISO8601 = "%Y-%m-%dT%H:%M:%S%z";
const std::string timestamp(char const* format) {
time_t raw_time;
time(&raw_time);
struct tm* time_info = localtime(&raw_time);
const size_t maxsize = 80;
char time_str[maxsize];
strftime(time_str, maxsize, format, time_info);
return time_str;
}
// Method 2: Class-based formatter used as a template parameter:
struct standard {
static inline char const* format() { return "%c"; }
};
struct iso8601 {
static inline char const* format() { return "%Y-%m-%dT%H:%M:%S%z"; }
};
// The formatter is supplied as a template parameter.
template<typename T>
const std::string timestamp() {
time_t raw_time;
time(&raw_time);
struct tm* time_info = localtime(&raw_time);
const size_t maxsize = 80;
char time_str[maxsize];
strftime(time_str, maxsize, T::format(), time_info);
return time_str;
}
int main() {
// Method 1: constant strings:
std::cout << timestamp(ISO8601) << std::endl;
// Method 2: template:
std::cout << timestamp<iso8601>() << std::endl;
}
想法?建议?我不太熟悉模板编程(特征、策略等),所以我真的很好奇其中一个是 "better" 或 "more correct" 而不是另一个。
如果您要命名不同的格式,并且想要一个常量名称
所有的呼叫站点,那么明显的解决方案是这样的:
extern char standard[] = "%c";
extern char iso8601[] = "%Y-%m-%dT%H:%M:%S%z";
// ...
template <char const* format>
std::string timestamp()
{
// ...
}
如果没有太多的命名格式,你甚至可以使用显式
专业化:
template <char const* format> std::string timestamp();
template<> std::string timestamp<standard>()
{
// ...
}
template <> std::string timestamp<iso8601>()
{
// ...
}
但是,如果您正在动态评估格式,我看不到在哪里
这些给你带来了很多好处 std::string timestamp( char const* format )
。
使用模板的唯一优势是解决方案
显式实例化确保你只会得到一个
已知格式;代码将无法编译并且 link 如果你
没有明确的实例化。这反过来意味着你不
需要任何额外的检查你的缓冲区是否足够大(你
无论如何都要省略——在你的两个实现中,有可能
用户给出一个会导致缓冲区溢出的人工字符串)。
我想知道是否可以考虑使用这两种提供格式字符串的方法之一 "more correct"。显然两者都有效,但一个需要在命名空间中维护一系列常量字符串,而另一个使用 class:
#include <ctime>
#include <iostream>
// Method 1: constant strings:
char const* STANDARD = "%c";
char const* ISO8601 = "%Y-%m-%dT%H:%M:%S%z";
const std::string timestamp(char const* format) {
time_t raw_time;
time(&raw_time);
struct tm* time_info = localtime(&raw_time);
const size_t maxsize = 80;
char time_str[maxsize];
strftime(time_str, maxsize, format, time_info);
return time_str;
}
// Method 2: Class-based formatter used as a template parameter:
struct standard {
static inline char const* format() { return "%c"; }
};
struct iso8601 {
static inline char const* format() { return "%Y-%m-%dT%H:%M:%S%z"; }
};
// The formatter is supplied as a template parameter.
template<typename T>
const std::string timestamp() {
time_t raw_time;
time(&raw_time);
struct tm* time_info = localtime(&raw_time);
const size_t maxsize = 80;
char time_str[maxsize];
strftime(time_str, maxsize, T::format(), time_info);
return time_str;
}
int main() {
// Method 1: constant strings:
std::cout << timestamp(ISO8601) << std::endl;
// Method 2: template:
std::cout << timestamp<iso8601>() << std::endl;
}
想法?建议?我不太熟悉模板编程(特征、策略等),所以我真的很好奇其中一个是 "better" 或 "more correct" 而不是另一个。
如果您要命名不同的格式,并且想要一个常量名称 所有的呼叫站点,那么明显的解决方案是这样的:
extern char standard[] = "%c";
extern char iso8601[] = "%Y-%m-%dT%H:%M:%S%z";
// ...
template <char const* format>
std::string timestamp()
{
// ...
}
如果没有太多的命名格式,你甚至可以使用显式 专业化:
template <char const* format> std::string timestamp();
template<> std::string timestamp<standard>()
{
// ...
}
template <> std::string timestamp<iso8601>()
{
// ...
}
但是,如果您正在动态评估格式,我看不到在哪里
这些给你带来了很多好处 std::string timestamp( char const* format )
。
使用模板的唯一优势是解决方案
显式实例化确保你只会得到一个
已知格式;代码将无法编译并且 link 如果你
没有明确的实例化。这反过来意味着你不
需要任何额外的检查你的缓冲区是否足够大(你
无论如何都要省略——在你的两个实现中,有可能
用户给出一个会导致缓冲区溢出的人工字符串)。