如何在编译时检查函数具有默认参数值?

问题描述

所有尝试做的就是制作这段代码

int main() {

    if constexpr( ??? ) {
        std::cout << "Yes\n";
        std::cout << f() << '\n';
        std::cout << f(42) << '\n';
    }
    else {
        std::cout << "No\n";
    }
    
    return 0;
}
  • 编译,如果函数 f 定义为这些示例中的任何一个
// Example 1
int f(int n = 0) { return n; }

// Example 2
int f(int n) { return n; }
int f() { return 0; }

// Example 3
int f(int n) { return n; }
  • 并为示例 Yes1 显示 2,并为示例 No 显示 3

这甚至可能吗?我想我见过有人用 SFINAE 做这件事,但我不记得它到底是怎么做的,以及我在哪里看到的。提前致谢。

解决方法

if constexpr 无法保护任何模板(例如,在 main 中)外部的格式错误的代码。显而易见的事情是编写一个接受 f 本身作为模板参数的模板,但要做到这一点,您必须具体化您的重载集。通常的做法是作为 SFINAE-friendly 函数对象:

template<class F,class=void>
constexpr bool opt=false;
template<class F>
constexpr bool opt<F,decltype(std::declval<F>()(1),void(std::declval<F>()()))> =true;

template<class F> int use(F &&x) {
  if constexpr(opt<F>) return x(1)+x();
  else return 0;
}

const auto f_=[](auto &&...aa) -> decltype(f(std::forward<decltype(aa)>(aa)...))
  {return f(std::forward<decltype(aa)>(aa)...);};

int main() {use(f_);}

在某些情况下,还可以选择创建一个“假”模板,该模板使用正式依赖的调用但始终使用您想要的类型,但这对于调用{{1} } 没有参数,如果您的 f() 需要一个参数,因为它不能依赖于模板参数,则立即格式错误(可能不需要诊断)。