【问题标题】:How to compare string_view using if-constexpt in a constexpr context如何在 constexpr 上下文中使用 if-constexpt 比较 string_view
【发布时间】:2023-03-18 17:40:01
【问题描述】:

是否可以在 constexpr 上下文中使用“if constexpr”比较 std::string_view?以及为什么 is_hello_2 和 is_hello_4 编译失败显示错误:“'s' is not a constant expression”

static constexpr bool is_hello_1(auto s) {
  return s == "hello";
}

static constexpr bool is_hello_2(auto s) {
    if constexpr (s == "hello") {
        return true;
    }
    return false;
}

static constexpr auto is_hello_3 = [](auto s) {
    return s == "hello";
};

static constexpr auto is_hello_4 = [](auto s) {
    if constexpr (s == "hello") {
        return true;
    }
    return false;
};

考虑主函数(https://godbolt.org/z/zEcnb8):

int main(int argc, char **argv) {
    static constexpr const std::string_view s1 ("hello");
    if constexpr (s1 == "hello"){}
    if constexpr (is_hello_1(s1)){}
    // if constexpr (is_hello_2(s1)){} // <- doesn't compile
    if constexpr (is_hello_3(s1)){}
    // if constexpr (is_hello_4(s1)){} // <- doesn't compile
    return 0;
}

有没有办法修复“is_hello_2”和“is_hello_4”?

【问题讨论】:

  • 每个问题请专注于一个问题。 “为什么编译器以如此不同的方式处理”部分相当不清楚。并请在问题中包含编译器错误消息
  • @idclev463035818 问题已更新

标签: c++ c++20 string-view if-constexpr


【解决方案1】:

我不会使用正式的标准措辞,而是解释问题。

if constexpr 要求其所有参数始终为constexpr

constexpr 函数的参数有时是 constexpr

您可以使用非constexpr 参数调用constexpr 函数。

试试consteval

#include <string_view>

using namespace std::literals;

consteval bool is_hello_1(auto s) {
  return s == "hello";
}

consteval bool is_hello_2(auto s) {
    if (s == "hello") {
        return true;
    }
    return false;
}


int main(int argc, char **argv) {

    static constexpr std::string_view s1 ("hello");
    static_assert(s1 == "hello");
    static_assert(is_hello_1(s1));
    static_assert(is_hello_2("hello"sv));
    return 0;
}

Live example

您可以将 consteval 放入通常放置 mutable 的 lambda 中(我不记得这是临时的,所以我没有在上面的示例代码中包含 lambda)。

最后,我建议对 C++ 文件本地的 static 函数使用匿名命名空间,并且不要在标头中使用。


这可能无法满足您的所有需求; if constexpr 的优点是您可以根据分支执行类型无效的操作。 C++ 不允许你根据函数参数的值做类型无效的事情。如果是这样,编译器无法在没有提供参数值的情况下编译函数体。

要解决这个问题,您可以执行一些操作,例如创建一个编译时字符串。

template<auto s>
consteval bool is_hello_2() {
  if constexpr (s == "hello") {
    return true;
  }
  return false;
}

并调用它

template<std::size_t N>
struct compile_time_string : std::array<char, N+1> {
    constexpr std::array<char, N+1>& buffer() { return *this; }
    constexpr std::array<char, N+1> const& buffer() const { return *this; }
    constexpr std::string_view view() const { return {this->data(), this->data()+this->size()}; }
    
private:
    template<std::size_t...Is>
    constexpr compile_time_string( char const* str, std::index_sequence<Is...> ):
        std::array<char, N+1>{{ str[Is]..., char(0) }}
    {}
public:
    explicit constexpr compile_time_string( char const* str ):
        compile_time_string( str, std::make_index_sequence<N>{} )
    {}
    explicit constexpr compile_time_string( std::array<char, N+1> buff ) :
        std::array<char, N+1>(buff)
    {}

    constexpr compile_time_string( compile_time_string const& ) = default;
    compile_time_string() = delete;
    
        
    constexpr auto operator<=>( compile_time_string const& o ) const = default;
    constexpr bool operator==( compile_time_string const& o ) const = default;
    
    template<std::size_t N_arg>
    friend constexpr auto operator==( char const(&lhs)[N_arg], compile_time_string const& rhs )
    {
        return std::string_view{ lhs, lhs+N_arg } == rhs.view();
    }
    template<std::size_t N_arg>
    friend constexpr auto operator==( compile_time_string const& lhs, char const(&rhs)[N_arg] )
    {
        return lhs.view() == std::string_view{ rhs, rhs+N_arg };
    }
};
template<std::size_t N>
compile_time_string( char const(&)[N] )->compile_time_string<N-1>;


template<auto s>
consteval bool is_hello_3() {
    if (s == "hello") {
        return true;
    }
    return false;
}


static_assert(is_hello_3<compile_time_string("hello")>());

Live example.

我减少了编译时间字符串。对于更多类型,您会想要更好的 和 == 等。

另外,我认为在 C++20 中,您可以制作“更强”的编译时字符串,其中该字符串实际上存在于自动参数中。但我不确定。

【讨论】:

    【解决方案2】:

    从函数的角度思考(好像你在函数范围内):如果函数参数未知,它如何在编译时解析你的代码?这与您在主函数中将s1 标记为constexpr 的原因相同。如果你不这样做 - 代码将无法编译。

    所以你要做的就是从is_hello2is_hello4 中删除constexpr。这并不妨碍函数在 constexpr 中的使用。

    #include <string_view>
    
    static constexpr bool is_hello_1(auto s) {
      return s == "hello";
    }
    
    static constexpr bool is_hello_2(auto s) {
        if (s == "hello") {
            return true;
        }
        return false;
    }
    
    static constexpr auto is_hello_3 = [](auto s) {
        return s == "hello";
    };
    
    static constexpr auto is_hello_4 = [](auto s) {
        if (s == "hello") {
            return true;
        }
        return false;
    };
    
    int main(int argc, char **argv) {
    
        static constexpr std::string_view s1 ("hello");
        static_assert(s1 == "hello");
        static_assert(is_hello_1(s1));
        static_assert(is_hello_2("hello"));
        static_assert(is_hello_3(s1));
        static_assert(is_hello_4(s1));
        return 0;
    }
    

    但是在类型和非类型模板参数上使用 if constexpr 是完全可以的:

    template<int s>
    static constexpr auto is_5 = []() {
        if constexpr (s == 5) {
            return true;
        }
        return false;
    };
    
    static_assert(is_5<5>());
    

    很遗憾,您现在不能将 std::string_view 作为非类型模板参数。

    【讨论】:

      【解决方案3】:

      有没有办法修复“is_hello_2”和“is_hello_4”?

      ifs 中的is_hello_2is_hello_4 中删除constexpr

      如何在 constexpr 上下文中使用 if-constexpt 比较 string_view

      通常,就像其他任何地方一样。

      static constexpr bool is_hello_5() {
          constexpr const std::string_view s1 ("hello");
          if constexpr (s1 == "hello") {
              return true;
          }
          return false;
      }
      

      函数参数值不是常量表达式,您不能在 if constexpr 中使用它们。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-23
        • 1970-01-01
        • 1970-01-01
        • 2019-07-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-29
        相关资源
        最近更新 更多