const char* 不能用作 std::char_traits<char>::length

问题描述 投票:0回答:3

我有以下代码:

constexpr uint32_t countWords(const char* str) {
    constexpr std::size_t length = std::char_traits<char>::length(str);
    std::uint32_t count = 0;
    for (std::size_t i = 0; i < length; i++) {
        if (str[i] == ' ') {
            count++;
        }
    }
    return count;
}

我的问题出现在函数的第一行,我得到一个语法错误:

str 不能用作常量

当我试图将它传递给

std::char_traits<char>::length
。如果我从
length
变量中删除 constexpr,错误就会消失,但对我来说,这意味着该变量在编译时不可获得,这违背了 constexpr 函数的目的。我使用字符串文字作为参数来调用这个函数。

std::char_traits::length

c++ c++17 constexpr string-literals compile-time
3个回答
3
投票

从评论来看,您似乎有兴趣在字符串文字上使用它。 要完成这项工作,您需要做的就是从

constexpr
中删除
length

函数必须在运行时和编译时都可以调用。

但是当你用字符串文字调用它时,它可以在编译时计算出来。您可以通过将函数的返回值分配给

constexpr
变量来验证这一点。

#include <iostream>
#include <string>

constexpr uint32_t countWords(const char* str) {
    std::size_t length = std::char_traits<char>::length(str);
    std::uint32_t count = 0;
    for (std::size_t i = 0; i < length; i++) {
        if (str[i] == ' ') {
            count++;
        }
    }
    return count;
}

int main()
{
    constexpr auto wordcount = countWords("This is a sentence");
    std::cout << wordcount;
}

1
投票

首先,您需要让您的编译器知道长度将在编译时计算。对于您当前的实现,

str
参数可以在编译时和运行时传递给函数调用(如果您不知道,
constexpr
不强制为编译时,它也可以在运行时执行;检查对于来自 C++20 的
consteval
,它强制编译时间计算)。

因此,为了确保您的

str
变量在编译时传递,您可能希望将其作为非类型模板参数传递,例如:

template <char const * S>
constexpr uint32_t countWords() {
    constexpr std::size_t length = std::char_traits<char>::length(S);
    std::uint32_t count = 0;
    for (std::size_t i = 0; i < length; i++) {
        if (S[i] == ' ') {
            count++;
        }
    }
    return count;
}

但是,请注意,如果您的S指针具有

static
存储,这将有效,因此以下将有效:

static constexpr char str[]{ "a b c" };
constexpr auto cnt = countWords<str>();

但以下将 NOT 工作:

constexpr char str[]{ "a b c" };
constexpr auto cnt = countWords<str>();  // ERROR

有关更多信息,请参阅此问题here.

除此之外,您的

countWords
函数没有做正确的事情,因为上面的示例会将变量
cnt
设置为值 2,这是不正确的。

编辑:

如果你想在字符串文字上使用函数,那么另一个答案描述了修复。


0
投票

另一个解决方案是避免 std::char_traits::length 并使用旧的、好的模板,它将在编译时为您提供数组大小:

constexpr const char words[] = "SOME WORDS AND MORE";

template <size_t length>
constexpr size_t countWords(const char (&str)[length]) {
    size_t count = 1;
    for (std::size_t i = 0; i < length; i++) {
        if (str[i] == ' ') {
            count++;
        }
    }
    return count;
}

int main() {
    constexpr auto words = countWords(words);
    printf("%d: ", words); // 4
}

附注。注意数组大小和字符串大小之间的差异。字符数组将包含零终止符。 附言。实际上它更像是 countSpaces 函数 :)

© www.soinside.com 2019 - 2024. All rights reserved.