2

经过一番摸索后,我设法对constexprJesteress 散列算法进行了 -ize。但是,编译器拒绝从cjesteress()调用中生成常量,例如 in ,而是使用andstd::cout << cjesteress("test) << std::endl;为调用生成代码。我做错什么了?clang-3.3gcc-4.8.1

#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);
}
4

1 回答 1

4

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

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

constexpr如果您用生成 a 的函数替换了这些强制转换uint32,那么您应该很高兴。

于 2013-08-20T21:02:16.897 回答