C++ check if statement can be evaluated constexpr

后端 未结 3 1054
无人共我
无人共我 2020-12-23 11:50

Is there a method to decide whether something can be constexpr evaluated, and use the result as a constexpr boolean? My simplified use case is as follows:

te         


        
相关标签:
3条回答
  • 2020-12-23 12:37

    Here's another solution, which is more generic (applicable to any expression, without defining a separate template each time).

    This solution leverages that (1) lambda expressions can be constexpr as of C++17 (2) the type of a captureless lambda is default constructible as of C++20.

    The idea is, the overload that returns true is selected when and only when Lambda{}() can appear within a template argument, which effectively requires the lambda invocation to be a constant expression.

    template<class Lambda, int=(Lambda{}(), 0)>
    constexpr bool is_constexpr(Lambda) { return true; }
    constexpr bool is_constexpr(...) { return false; }
    
    template <typename base>
    class derived
    {
        // ...
    
        void execute()
        {
            if constexpr(is_constexpr([]{ base::get_data(); }))
                do_stuff<base::get_data()>();
            else
                do_stuff(base::get_data());
        }
    }
    
    0 讨论(0)
  • 2020-12-23 12:40

    Not exactly what you asked (I've developer a custom type trait specific for a get_value() static method... maybe it's possible to generalize it but, at the moment, I don't know how) but I suppose you can use SFINAE and make something as follows

    #include <iostream>
    #include <type_traits>
    
    template <typename T>
    constexpr auto icee_helper (int)
       -> decltype( std::integral_constant<decltype(T::get_data()), T::get_data()>{},
                    std::true_type{} );
    
    template <typename>
    constexpr auto icee_helper (long)
       -> std::false_type;
    
    template <typename T>
    using isConstExprEval = decltype(icee_helper<T>(0));
    
    template <typename base>
    struct derived
     {
       template <std::size_t I>
       void do_stuff()
        { std::cout << "constexpr case (" << I << ')' << std::endl; }
    
       void do_stuff (std::size_t i)
        { std::cout << "not constexpr case (" << i << ')' << std::endl; }
    
       void execute ()
        {
          if constexpr ( isConstExprEval<base>::value )
             do_stuff<base::get_data()>();
          else
             do_stuff(base::get_data());
        }
     };
    
    struct foo
     { static constexpr std::size_t get_data () { return 1u; } };
    
    struct bar
     { static std::size_t get_data () { return 2u; } };
    
    int main ()
     { 
       derived<foo>{}.execute(); // print "constexpr case (1)"
       derived<bar>{}.execute(); // print "not constexpr case (2)"
     }
    
    0 讨论(0)
  • 2020-12-23 12:42
    template<auto> struct require_constant;
    template<class T>
    concept has_constexpr_data = requires { typename require_constant<T::get_data()>; };
    

    This is basically what's used by std::ranges::split_view.

    0 讨论(0)
提交回复
热议问题