C ++检查语句是否可以评估为constexpr

时间:2019-03-21 20:10:38

标签: c++ template-meta-programming constexpr c++20 if-constexpr

是否有一种方法可以确定是否可以对constexpr求值,并将结果用作constexpr布尔值?我的简化用例如下:

belongsTo

我的目标是C ++ 2a。

我找到了以下reddit线程,但我不是宏的忠实拥护者。 https://www.reddit.com/r/cpp/comments/7c208c/is_constexpr_a_macro_that_check_if_an_expression/

3 个答案:

答案 0 :(得分:16)

这是另一个解决方案,它更通用(适用于任何表达式,而无需每次都定义单独的模板)。

此解决方案利用了(1)Lambda表达式从C ++ 17开始可以是constexpr(2)无捕获Lambda的类型从C ++ 20开始是默认可构造的。

这个想法是,只有当true可以出现在模板参数中时,才选择返回Lambda{}()的重载,这实际上要求lambda调用是一个常量表达式。

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

答案 1 :(得分:11)

并不是您所要的(我为get_value()静态方法开发了一个自定义类型特征...也许可以将其概括化,但是目前我不知道如何)我想您可以使用SFINAE并进行以下操作

#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)"
 }

答案 2 :(得分:7)

template<auto> struct require_constant;
template<class T>
concept has_constexpr_data = requires { typename require_constant<T::get_data()>; };

这基本上是std::ranges::split_view使用的。