I am trying to compile a class using Clang:
#include <string>
#include <type_traits>
#include <cstdlib>
struct foo
{
template <class T, class... Ts>
struct is_any: std::disjunction <std::is_same <T, Ts>... >{};
template<typename T, std::size_t N>
static constexpr bool is_pointer_to_const_char(T(&)[N])
{
return std::is_same_v<const char, T>;
}
template<typename T>
static constexpr bool is_pointer_to_const_char(T &&)
{
return std::is_same_v<const char *, T>;
}
template <class T>
static constexpr bool is_str( const T& obj )
{
return is_pointer_to_const_char( obj ) || is_any<T, std::string, std::string_view>::value;
}
static constexpr bool is_escape_v( const std::string_view& str )
{
return ! str.rfind( "\033", 0 );
}
template <class T>
inline bool is_escape( const T& str ) const
{
if constexpr ( is_str( str ) ) return is_escape_v( str );
return false;
}
};
int main()
{
foo obj;
obj.is_escape( "test" );
}
But I get the following error:
prove.cpp:36:28: error: constexpr if condition is not a constant expression
if constexpr ( is_str( str ) ) return is_escape_v( str );
^
prove.cpp:44:7: note: in instantiation of function template specialization 'foo::is_escape<char [5]>' requested here
obj.is_escape( "test" );
^
1 error generated.
It seems that it doesn't like the constexpr
qualifier I used in the if
condition in the is_escape()
method.
Did I do something wrong in the class method's definition?
My Clang version is 10.0.0-4.
CodePudding user response:
Did I do something wrong in the class method's definition?
The problem is that function parameters (like str
) are not constant expressions. For example, we cannot use str
as a template non-type parameter, or as a size of a built-in array.
This means the expression is_str( str )
that contains the subexpression str
is itself not a constant expression, either.
Moreover, the code is rejected by all the three major compilers, if you're using their latest versions. Demo
A simpler way of doing this would be as shown below:
template <typename T>
bool is_escape(const T& str)
{
if constexpr(std::is_convertible_v<T, std::string>)
{
return ! std::string(str).rfind( "\033", 0 );
}
else
{
return false;
}
}