繁体   English   中英

使用 constexpr 作为 std::array 大小

[英]Using constexpr as std::array size

我有以下代码使用constexpr作为数组大小。

#include <array>

template <size_t size>
constexpr size_t
GetSize(const char(&format)[size])
{
    // Iterate over format array and compute a value.
    size_t count = 0;
    for (size_t i = 0; i < size; ++i)
    {
        if (format[i] == '%')
        {
            ++count;
        }
    }

    return count;
}

template <size_t size>
constexpr auto
GetArray(const char(&format)[size])
{
    constexpr size_t arraySize = GetSize(format);
    return std::array<char, arraySize>();
}

int main(int argc, char** argv)
{
    static_assert(GetArray("hello").size() == 12, "failed");
}

但是,这无法在 VS2019 下编译,并出现以下错误

error C2131:  expression did not evaluate to a constant
message :  failure was caused by a read of a variable outside its lifetime
message :  see usage of 'format'
message :  see reference to function template instantiation 'auto GetArray<6>(const char (&)[6])' being compiled

这是编译器错误吗? 如果是这样,是否有解决方法?

我不知道您是否绝对需要GetSize() function 用于其他目的,但是在您的 GetArray 中您已经可以访问数组的长度,因此您可以这样做:

#include <array>

template <std::size_t N>
constexpr auto
GetArray(const char(&format)[N])
{
    return std::array<char, N*2>{};
}

int main(int argc, char** argv)
{
    static_assert(GetArray("hello").size() == 12, "failed");
}

constexpr 函数的问题是,您可以使用 constexpr arguments 以及非 constexpr arguments 调用:

int constexpr f(int n)
{
    return ++n;
}

int constexpr n0 = 7;
int n1; std::cin >> n1;
f(n0); // result IS constexpr
f(n1); // result is NOT constexpr, just an ordinary int

由于这个特性,function 参数本身不能是 constexpr,或者更准确地说,不能在 constexpr 上下文中使用。 所以在你的 function 中:

constexpr size_t arraySize = getSize(format);
//                                      ^ cannot be used as constexpr, even if
//                                        constexpr has been passed to, so result
//                                        not either (the f(n1) case above)

您可以稍微修改您的第二个 function :

template <size_t Size>
constexpr auto
getArray()
{
    return std::array<char, Size>();
}

并像使用它一样

int main(int argc, char** argv)
{
    static_assert(getArray<getSize("hello")>().size() == 0, "failed");
    return 0;
}

当然,现在看起来很丑,但是你可能会躲在一个宏后面:

#define myGetArray(STRING) getArray<getSize(STRING)>()

或者干脆

#define getArray(STRING) std::array<char, getSize(STRING)>()

这是使用 lambda 将 char 数组包装为 constexpr 的 C++17 工作解决方案。

#include <array>
#include <string>

template <typename Char_Array_Holder>
constexpr size_t GetSize(Char_Array_Holder holder)
{
  // Iterate over format array and compute a value.
  constexpr std::string_view format = holder();

  size_t count = 0;
  for (char c : format)
  {
    if (c == '%')
    {
      ++count;
    }
  }

  return count;
}

template <typename Char_Array_Holder>
constexpr auto GetArray(Char_Array_Holder holder)
{
  constexpr size_t arraySize = GetSize(holder);
  return std::array<char, arraySize>();
}

#define hold(msg) []() { return msg; }

int main(int argc, char** argv)
{
  static_assert(GetArray(hold("hello")).size() == 0, "failed...");
  static_assert(GetArray(hold("h%ello")).size() == 1, "failed...");
  static_assert(GetArray(hold("h%el%%lo")).size() == 3, "failed...");
}

改编自 编译时字符串解析,您可以阅读以获取更多信息

GCC 在这里接受此代码是错误的。

GetArray 正文中的format不是constexpr (它是对size为 const char 的数组的引用),因此,它不能在另一个constexpr function 中用作constexpr 请注意size一个constexpr所以你应该使用它来代替:

#include <array>


inline constexpr size_t GetSize(size_t size) { return size * 2; }

template <size_t size>
constexpr auto
GetArray(const char(&format)[size])
{
    constexpr size_t s = GetSize(size);
    return std::array<char, s>();
}

int main(int argc, char** argv)
{
    static_assert(GetArray("hello").size() == 12, "failed");
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM