Я не буду использовать формальную стандартную формулировку, а скорее объясню проблему.
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;
}
Живой пример
Вы можете поместить consteval
в лямбду там, где вы обычно помещаете изменяемый (я не вспомнил об этом, поэтому я не включил лямбды в свой пример кода выше).
Наконец, я бы посоветовал использовать анонимные пространства имен для 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")>());
Живой пример.
Я урезал строку времени компиляции. Вы захотите лучше ‹=› и == и тому подобное для большего количества типов.
Кроме того, я думаю, что в C ++ 20 вы можете сделать более сильные строки времени компиляции, где строка фактически живет в аргументе auto. Но я не уверен.
person
Yakk - Adam Nevraumont
schedule
19.10.2020