简体   繁体   English

使用 constexpr 作为 std::array 大小

[英]Using constexpr as std::array size

I have the following code that uses a constexpr as the 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");
}

This however fails to compile under VS2019 with the following error但是,这无法在 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

Is this a compiler bug?这是编译器错误吗? If so, is there a workaround for this?如果是这样,是否有解决方法?

I do not know if you absolutely need the GetSize() function for some other purpose, but in your GetArray you already have access to the length of the array so you could just do this:我不知道您是否绝对需要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");
}

The problem with constexpr functions is, that you can call the with both constexpr arguments as well as with non-constexpr arguments: 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

Because of this characteristic the function parameters themselves cannot be constexpr, or more precisely, cannot be used in constexpr contexts.由于这个特性,function 参数本身不能是 constexpr,或者更准确地说,不能在 constexpr 上下文中使用。 So in your function as well:所以在你的 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)

You could modify your second function a bit:您可以稍微修改您的第二个 function :

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

And use it like并像使用它一样

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

Sure, looks rather ugly now, you might hide behind a macro, though:当然,现在看起来很丑,但是你可能会躲在一个宏后面:

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

or simply或者干脆

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

Here is a C++17 working solution using lambda to wrap the char array as a constexpr.这是使用 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...");
}

Adapted from compile-time-string-parsing you can read to get futher information改编自 编译时字符串解析,您可以阅读以获取更多信息

GCC is wrong in accepting this code here. GCC 在这里接受此代码是错误的。

The format in GetArray body is not a constexpr (it's a reference to a array of size const char), and as such, it can't be used in another constexpr function as a constexpr . GetArray 正文中的format不是constexpr (它是对size为 const char 的数组的引用),因此,它不能在另一个constexpr function 中用作constexpr Please notice that size is a constexpr so you should use that instead:请注意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