Home > Net >  Why do I get this error in Clang? "constexpr if condition is not a constant expression"
Why do I get this error in Clang? "constexpr if condition is not a constant expression"

Time:07-27

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;
    }
   
}

Working demo

  • Related