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

问题描述

我有以下代码

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

解决方法

从评论来看,您似乎有兴趣在字符串文字上使用它。 您需要做的就是从 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;
}
,

首先,您需要让编译器知道长度将在编译时计算。对于您当前的实现,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 constexpr char str[]{ "a b c" };
constexpr auto cnt = countWords<str>();

但以下操作不起作用

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

有关详细信息,请参阅此问题 here

除此之外,您的 countWords 函数没有做正确的事情,因为上面的示例将变量 cnt 设置为不正确的值 2。

编辑:

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