我做了很多在我的计划散列的,所以我决定砍了constexpr功能,可以在做编译期至少一些散列的我时间。在成功实现constexpr散列函数之后,我对代码进行了剖析,实际上需要时间 - 这很奇怪,因为计算应该在编译时发生,而不是运行时发生。使用G ++ 4.7.3。与常量字符数组参数剖析constexpr显示运行时执行
下面是一个有点gprof的输出,以及一个演示程序完成一个非constexpr实施以来,constexpr的功能是很难读,也表明它的工作原理。
我从以下链接所采取的意见和作出的字符数组constexpr以及常量: why is a const array not accessible from a constexpr function?
注:有些东西已经从代码中删除,以简化这个演示,如测试和断言。
1.)我的constexpr函数是否在运行时执行? (看起来很明显他们是)
2.)如果是这样,为什么?我该如何让它在编译时而不是运行时执行?
gprof的:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls us/call us/call name
50.00 0.06 0.06 600012 0.09 0.09 string_length(char const*, unsigned int)
36.36 0.10 0.04 50001 0.80 2.20 HASHOAT_CONSTEXPR(char const*, unsigned int, unsigned int, unsigned int)
9.09 0.10 0.01 1100022 0.01 0.01 oat_part_two(unsigned int const&)
4.55 0.11 0.01 50001 0.10 0.10 oat_part_six(unsigned int const&)
0.00 0.11 0.00 1650033 0.00 0.00 oat_part_one(unsigned int const&, char)
0.00 0.11 0.00 550011 0.00 0.00 oat_part_three(unsigned int const&)
0.00 0.11 0.00 200004 0.00 0.00 oat_part_four(unsigned int const&)
0.00 0.11 0.00 100002 0.00 0.00 oat_part_five(unsigned int const&)
0.00 0.11 0.00 1 0.00 0.00 HashOAT(char const*, unsigned int)
演示程序:
#include <cstdio>
#include <cstring>
// "One-at-a-time" Hash
// the non-constexpr implementation:
unsigned int HashOAT(const char *key, const unsigned int size = 1009); // size must be prime
unsigned int HashOAT(const char *key, const unsigned int size) {
unsigned int h = 0;
const std::size_t len = strlen(key);
for (std::size_t i = 0; i < len; ++i) {
h += static_cast< unsigned int >(key[i]);
h += (h << 10);
h ^= (h >> 6);
}
h += (h << 3);
h ^= (h >> 11);
h += (h << 15);
return h % size;
}
constexpr unsigned int HASHOAT_CONSTEXPR(const char* str, const std::size_t size=1009, const std::size_t idx=0, const std::size_t h=0);
constexpr unsigned int oat_part_one(const std::size_t& h, const char c);
constexpr unsigned int oat_part_two(const std::size_t& h);
constexpr unsigned int oat_part_three(const std::size_t& h);
constexpr unsigned int oat_part_four(const std::size_t& h);
constexpr unsigned int oat_part_five(const std::size_t& h);
constexpr unsigned int oat_part_six(const std::size_t& h);
constexpr unsigned int oat_part_one(const std::size_t& h, const char c) {
return (h + static_cast<unsigned int>(c));
}
constexpr unsigned int oat_part_two(const std::size_t& h) {
return (h << 10);
}
constexpr unsigned int oat_part_three(const std::size_t& h) {
return (h >> 6);
}
constexpr unsigned int oat_part_four(const std::size_t& h) {
return (h << 3);
}
constexpr unsigned int oat_part_five(const std::size_t& h) {
return (h >> 11);
}
constexpr unsigned int oat_part_six(const std::size_t& h) {
return (h << 15);
}
constexpr std::size_t string_length(const char* str, std::size_t index = 0) {
return (str == nullptr || str[index] == '\0') ? 0 : 1 + string_length(str, index+1);
}
constexpr unsigned int HASHOAT_CONSTEXPR(const char* str, const std::size_t size, const std::size_t idx, const std::size_t h) {
return (
(idx == string_length(str)) ? (
(
(
(h + oat_part_four(h))^
oat_part_five(h + oat_part_four(h))
) +
oat_part_six(
(h + oat_part_four(h))^
oat_part_five(h + oat_part_four(h))
)
) % size
) : (
HASHOAT_CONSTEXPR(str, size, idx+1,
(
oat_part_one(h, str[idx]) +
oat_part_two(h + static_cast< unsigned int>(str[idx]))
)^
oat_part_three(oat_part_one(h, str[idx]) +
oat_part_two(oat_part_one(h, str[idx]))
)
)
)
);
}
int main (void) {
constexpr const char* str="Some String";
printf("Hash: %i\n", HashOAT(str));
printf("Hash: %i\n", HASHOAT_CONSTEXPR(str));
// make the program take some time so we can see if the constexpr function is actually taking run-time
for (int i=0; i<50000; ++i) {
HASHOAT_CONSTEXPR(str);
}
return 0;
}
这里是最近的讨论(阅读:参数)约在Slashdot constexpr,与VC2013,但仍然具有现实意义: http://developers.slashdot.org/comments.pl?sid=4349323&cid=45158845 – Brandon