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

问题描述

是否可以在constexpr上下文中使用“ if constexpr”比较std :: string_view?为什么is_hello_2和is_hello_4无法编译并显示错误:“‘s’不是常量表达式”

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”?

解决方法

是否可以解决“ is_hello_2”和“ is_hello_4”?

constexprif中的is_hello_2中删除is_hello_4

如何在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中使用它们。

,

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

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放在通常可变的lambda中(我不记得这一点,因此我在上面的示例代码中没有包含lambda)。

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


这可能无法满足您的所有需求; 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中,您可以使“更强”的编译时间字符串实际位于自动自变量中。但是我不确定。

,

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

因此,您要做的是从constexpris_hello2中删除is_hello4。这不会阻止该函数在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;
}

但是如果在类型和非类型模板参数上使用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作为非类型模板参数。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...