我想定义可以在不同文件中打开和关闭的计时器,而无需考虑必须在哪里声明它们以及它们的范围应该是什么。所以我选择使用包装在带有内联静态变量的类中的全局变量,并且该类由计时器的名称模板化:
#include <chrono>
#include <algorithm>
template<size_t N>
struct StringLiteral
{
constexpr StringLiteral(const char (&str)[N]) {std::copy_n(str, N, value);}
char value[N];
};
template<StringLiteral>
struct GlobalTimer
{
inline static std::chrono::system_clock::time_point startTime = std::chrono::system_clock::now();
inline static double totalTime = 0;
inline static void on()
{
startTime = std::chrono::system_clock::now();
}
inline static void off()
{
auto endTime = std::chrono::system_clock::now();
totalTime += std::chrono::duration<double>(endTime - startTime).count();
}
inline static double get()
{
return totalTime;
}
};
在实践中我这样使用它们:
GlobalTimer<"myFirstTimer">::on();
//do some stuff
GlobalTimer<"myFirstTimer">::off();
//eventually in another file
std::cout << "myFirstTimer : " << GlobalTimer<"myFirstTimer">::get() << std::endl;
但是,有一个问题我无法理解。在我的多文件代码中,这个
get()
函数始终返回 0,而当我在较小的示例上尝试时它会起作用。此外,当我在 std::cout << totalTime << std::endl
函数的 return 语句之前添加 get()
时,计时器开始工作并且不再返回 0。所以我以为是编译器优化问题,但是我尝试在debug中编译,用gcc和clang,结果是一样的。现在我认为这可能是一种未定义的行为,所以我来这里是为了了解真相:)。
[编辑]
为了消除字符串文字唯一性的不确定性,我尝试了以下方法:
constexpr char myFirstTimer[10] = "myFirstTimer";
GlobalTimer<myFirstTimer>::on();
//do some stuff
GlobalTimer<myFirstTimer>::off();
//in the same file this time
std::cout << "myFirstTimer : " << GlobalTimer<myFirstTimer>::get() << std::endl;
这并不能解决问题,它返回0...
事实上,当您创建
GlobalTimer<"myFirstTimer">
的实例时,它会生成不同的类型,即每种类型的每个静态成员和函数。
模板参数应使用
typename
或 class
关键字,或者是整数。
可能(因为它的 UB)在你的情况下指针被视为数字(地址),为每个新地址创建不同的类型。
这里是解释:传递 const char* 作为模板参数