是否可以在编译时执行唯一的字符串到 int 映射?\n假设我有一个这样的模板用于分析:
\n\ntemplate <int profilingID>\nclass Profile{\npublic:\n Profile(){ /* start timer */ }\n ~Profile(){ /* stop timer */ }\n};\nRun Code Online (Sandbox Code Playgroud)\n\n我将其放在函数调用的开头,如下所示:
\n\nvoid myFunction(){\n Profile<0> profile_me;\n\n /* some computations here */\n}\nRun Code Online (Sandbox Code Playgroud)\n\n现在我正在尝试做类似以下的事情,这是不可能的,因为字符串文字不能用作模板参数:
\n\nvoid myFunction(){\n Profile<"myFunction"> profile_me; // or PROFILE("myFunction")\n\n /* some computations here */\n}\nRun Code Online (Sandbox Code Playgroud)\n\n我可以声明全局变量来解决这个问题,但我认为避免以前的声明会更优雅。表格的简单映射
\n\n就足够了。但到目前为止,无论使用 constexpr、模板元编程还是宏,我都无法找到完成此类映射的方法。有任何想法吗?
\n正如@harmic在评论中已经提到的,您可能应该将名称传递给构造函数。这也可能有助于减少代码膨胀,因为您不必为每个函数生成新类型。
然而,我不想错过展示一个肮脏的黑客的机会,这在字符串无法传递给构造函数的情况下可能有用。如果字符串的最大长度在编译时已知,则可以将它们编码为整数。在下面的示例中,我仅使用单个整数,它将系统上的最大字符串长度限制为 8 个字符。将方法扩展到多个整数(通过小宏方便地隐藏分割逻辑)留给读者作为练习。
该代码利用 C++14 功能在constexpr函数中使用任意控制结构。在 C++11 中,您必须编写wrap稍微不那么直接的递归函数。
#include <climits>
#include <cstdint>
#include <cstdio>
#include <type_traits>
template <typename T = std::uintmax_t>
constexpr std::enable_if_t<std::is_integral<T>::value, T>
wrap(const char *const string) noexcept
{
constexpr auto N = sizeof(T);
T n {};
std::size_t i {};
while (string[i] && i < N)
n = (n << CHAR_BIT) | string[i++];
return (n << (N - i) * CHAR_BIT);
}
template <typename T>
std::enable_if_t<std::is_integral<T>::value>
unwrap(const T n, char *const buffer) noexcept
{
constexpr auto N = sizeof(T);
constexpr auto lastbyte = static_cast<char>(~0);
for (std::size_t i = 0UL; i < N; ++i)
buffer[i] = ((n >> (N - i - 1) * CHAR_BIT) & lastbyte);
buffer[N] = '\0';
}
template <std::uintmax_t Id>
struct Profile
{
char name[sizeof(std::uintmax_t) + 1];
Profile()
{
unwrap(Id, name);
std::printf("%-8s %s\n", "ENTER", name);
}
~Profile()
{
std::printf("%-8s %s\n", "EXIT", name);
}
};
Run Code Online (Sandbox Code Playgroud)
它可以这样使用:
void
function()
{
const Profile<wrap("function")> profiler {};
}
int
main()
{
const Profile<wrap("main")> profiler {};
function();
}
Run Code Online (Sandbox Code Playgroud)
输出:
#include <climits>
#include <cstdint>
#include <cstdio>
#include <type_traits>
template <typename T = std::uintmax_t>
constexpr std::enable_if_t<std::is_integral<T>::value, T>
wrap(const char *const string) noexcept
{
constexpr auto N = sizeof(T);
T n {};
std::size_t i {};
while (string[i] && i < N)
n = (n << CHAR_BIT) | string[i++];
return (n << (N - i) * CHAR_BIT);
}
template <typename T>
std::enable_if_t<std::is_integral<T>::value>
unwrap(const T n, char *const buffer) noexcept
{
constexpr auto N = sizeof(T);
constexpr auto lastbyte = static_cast<char>(~0);
for (std::size_t i = 0UL; i < N; ++i)
buffer[i] = ((n >> (N - i - 1) * CHAR_BIT) & lastbyte);
buffer[N] = '\0';
}
template <std::uintmax_t Id>
struct Profile
{
char name[sizeof(std::uintmax_t) + 1];
Profile()
{
unwrap(Id, name);
std::printf("%-8s %s\n", "ENTER", name);
}
~Profile()
{
std::printf("%-8s %s\n", "EXIT", name);
}
};
Run Code Online (Sandbox Code Playgroud)