2013-08-20 58 views
2

经过一些头部划伤,我设法constexpr -ize Jesteress哈希算法。然而,编译器拒绝从cjesteress()调用中产生一个常量,例如在std::cout << cjesteress("test) << std::endl;中,但是为clang-3.3和这两个调用生成代码。我做错了什么?constexprizing化jesteress哈希算法

#include <cstdint> 

#include <cstring> 

#include <string> 

#define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n)))) 

namespace detail 
{ 

constexpr std::uint32_t const PRIME(709607u); 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::size_t cstrlen(char const* const p, 
    std::size_t const s = 0) 
{ 
    return *p ? cstrlen(p + 1, s + 1) : s; 
} 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::uint32_t case4(char const*& p, std::size_t const wrdlen, 
    std::uint32_t hash32) 
{ 
    return wrdlen & sizeof(std::uint32_t) 
    ? hash32 = (hash32^*(std::uint32_t*)p) * PRIME, 
     p += sizeof(std::uint32_t), 
     hash32 
    : hash32; 
} 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::uint32_t case2(char const*& p, std::size_t const wrdlen, 
    std::uint32_t hash32) 
{ 
    return wrdlen & sizeof(std::uint16_t) 
    ? hash32 = (hash32^*(std::uint16_t*)p) * PRIME, 
     p += sizeof(std::uint16_t), 
     hash32 
    : hash32; 
} 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::uint32_t case1(char const* p, std::size_t const wrdlen, 
    std::uint32_t hash32) 
{ 
    return wrdlen & 1 
    ? hash32 = (hash32^*p) * PRIME 
    : hash32; 
} 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::uint32_t cjesteress(char const* p, std::size_t wrdlen, 
    std::uint32_t hash32) 
{ 
    return wrdlen >= 2 * sizeof(std::uint32_t) 
    ? cjesteress(p + 2 * sizeof(std::uint32_t), 
     wrdlen - 2 * sizeof(std::uint32_t), 
     (hash32^(ROL(*(std::uint32_t *)p, 5)^*(std::uint32_t *)(p + 4))) 
      * ::detail::PRIME) 
    : (hash32 = ::detail::case4(p, wrdlen, hash32), 
     hash32 = ::detail::case2(p, wrdlen, hash32), 
     hash32 = ::detail::case1(p, wrdlen, hash32), 
     hash32^(hash32 >> 16)); 
} 

} 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::uint32_t cjesteress(char const* const p) 
{ 
    return ::detail::cjesteress(p, ::detail::cstrlen(p), 2166136261u); 
} 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::uint32_t cjesteress(char const* const p, 
    std::size_t const wrdlen) 
{ 
    return ::detail::cjesteress(p, wrdlen, 2166136261u); 
} 

的错误是一个神秘的:

testjesteress.cpp:16:33: in constexpr expansion of 
'cjesteress(((const char*)"1234567890"))' 
../resource/jesteress.hpp:78:67: in constexpr expansion of 
'detail::cjesteress(((const char*)p), detail::cstrlen(((const 
char*)p), 0ul), 2166136261u)' testjesteress.cpp:16:33: error: 
accessing value of '"1234567890"' through a 'uint32_t {aka unsigned 
int}' glvalue in a constant expression 
    case cjesteress("1234567890"): 
           ^

编辑:这里是一个工作的实施,感谢所有:

#include <cstdint> 

#include <cstring> 

#define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n)))) 

namespace detail 
{ 

static constexpr std::uint32_t const PRIME(709607u); 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::size_t cstrlen(char const* const p, 
    std::size_t const s = 0) 
{ 
    return *p ? cstrlen(p + 1, s + 1) : s; 
} 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::uint32_t p2u32(char const* const p) 
{ 
    return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; 
} 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::uint16_t p2u16(char const* const p) 
{ 
    return p[0] | p[1] << 8; 
} 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::uint32_t case0(std::uint32_t const hash32) 
{ 
    return hash32^(hash32 >> 16); 
} 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::uint32_t case1(char const* const p, 
    std::size_t const wrdlen, std::uint32_t const hash32) 
{ 
    return wrdlen & 1 
    ? case0((hash32^*p) * PRIME) 
    : case0(hash32); 
} 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::uint32_t case2(char const* const p, 
    std::size_t const wrdlen, std::uint32_t const hash32) 
{ 
    return wrdlen & sizeof(std::uint16_t) 
    ? case1(p + sizeof(std::uint16_t), wrdlen, (hash32^p2u16(p)) * PRIME) 
    : case1(p, wrdlen, hash32); 
} 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::uint32_t case4(char const* const p, 
    std::size_t const wrdlen, std::uint32_t const hash32) 
{ 
    return wrdlen & sizeof(std::uint32_t) 
    ? case2(p + sizeof(std::uint32_t), wrdlen, (hash32^p2u32(p)) * PRIME) 
    : case2(p, wrdlen, hash32); 
} 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::uint32_t cjesteress(char const* const p, 
    std::size_t const wrdlen, std::uint32_t const hash32) 
{ 
    return wrdlen >= 2 * sizeof(std::uint32_t) 
    ? cjesteress(p + 2 * sizeof(std::uint32_t), 
     wrdlen - 2 * sizeof(std::uint32_t), 
     (hash32^(ROL(p2u32(p), 5)^p2u32(p + 4))) 
      * ::detail::PRIME) 
    : ::detail::case4(p, wrdlen, hash32); 
} 

} 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::uint32_t cjesteress(char const* const p) 
{ 
    return ::detail::cjesteress(p, ::detail::cstrlen(p), 2166136261u); 
} 

////////////////////////////////////////////////////////////////////////////// 
inline constexpr std::uint32_t cjesteress(char const* const p, 
    std::size_t const wrdlen) 
{ 
    return ::detail::cjesteress(p, wrdlen, 2166136261u); 
} 
+1

你没有显示整个段,在哪里调用'case cjesteress(“1234567890”):'? – TemplateRex

+0

@TemplateRex我想给出一个提示,至于什么可能是问题。代码编译正常,但在switch语句中使用它会产生错误。 – user1095108

+2

编译只是作业的一半,因为constexpr可以在运行时和编译时之间进行选择。 “开关”本身是否是“constexpr”的一部分?因为那只会在C++ 14中工作(clang -std = C++ 1y) – TemplateRex

回答

4

我的猜测是,编译器不喜欢你通过将部分字符转换为uint32_t来访问字符串中的字符(因为它违反了严格的别名并且是未定义的行为,至少在字节顺序方面):

(hash32^(ROL(*(std::uint32_t *)p, 5)^*(std::uint32_t *)(p + 4))) 
      * ::detail::PRIME) 

如果替换为生成的uint32,而不是constexpr功能的铸件,你要善于去。

+0

关于此标准的任何内容,还是编译器反复无常的情况? – user1095108

+2

@ user1095108“它违反了严格的别名”,所以它直接违背标准。 – 2013-08-20 21:04:51

+0

另外,@ MSN,它是UB,而不是IB。 – 2013-08-20 21:05:24