【问题标题】:Using SFINAE to check whether function is constexpr or not使用 SFINAE 检查函数是否为 constexpr
【发布时间】:2020-12-08 05:35:06
【问题描述】:

我想检查是否可以在编译期间评估函数。我找到了this,但我并不完全理解这个概念。我有几个疑问:

  1. 代码中下面这行的作用是什么?
    template<int Value = Trait::f()>

  2. 每次需要检查函数是否可编译时,是否需要将其设为某个结构的成员函数?

PS
我复制链接中的代码,只是为了方便。

template<typename Trait>
struct test
{
    template<int Value = Trait::f()>
    static std::true_type do_call(int){ return std::true_type(); }

    static std::false_type do_call(...){ return std::false_type(); }

    static bool call(){ return do_call(0); }
};

struct trait
{
    static int f(){ return 15; }
};

struct ctrait
{
    static constexpr int f(){ return 20; }
};

int main()
{
   std::cout << "regular: " << test<trait>::call() << std::endl;
   std::cout << "constexpr: " << test<ctrait>::call() << std::endl;
}

【问题讨论】:

  • 从总体上看,这里经常发布更多无用的问题,所以这里是一个赞成票,以抵消反对票。不要太在意偏离投票,它们只是附带损害......
  • template&lt;int Value = Trait::f()&gt; 实际上要求可以在编译时评估 Trait::f()。如果不能,则此重载不参与重载决议。如果存在,则它是 do_call(0); 的最佳匹配,但如果它被淘汰,则 do_call(...) 成为最佳匹配。
  • 另一个问题是constexpr 函数可能只用于给定可能参数子集的常量表达式。所以f(0) 无效,而f(42) 是(constexpr int f(int i) { if (i == 0) throw std::runtime_error(".."); return i;}

标签: c++ templates constexpr sfinae compile-time


【解决方案1】:

这里只是一个简单的示例,您可以使用 std::void_t 来解决您的第 2 点,它在某种程度上可能是通用的...

#include <iostream>
#include <type_traits>

int f() {
    return 666;
}

constexpr int cf(int, double) {
    return 999;
}

template <auto F>
struct indirection {
};

template<typename F, class = std::void_t<> >
struct is_constexpr : std::false_type { };

template<typename F, typename... Args>
struct is_constexpr<F(Args...),
           std::void_t<indirection<F(Args{}...)>>
       > : std::true_type { };

int main()
{
   std::cout << is_constexpr<decltype(f)>::value << std::endl;
   std::cout << is_constexpr<decltype(cf)>::value << std::endl;
};

Demo here

【讨论】:

  • 值未声明。
  • @Kishan Shukla 我添加了一个演示链接
  • 请注意,您只检查cf(0, 0) 是否可以在常量表达式中使用。其他值可能无效,并且您要求您的参数是默认的 constexpr 可构造的。
猜你喜欢
  • 2013-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多