如何在编译时检查函数是否被调用

时间:2014-09-03 22:30:00

标签: c++

我试图在编译时确定是否曾调用过某个函数。具体来说,如果是:

,我想抛出一个静态断言失败
template <typename T>
auto Function(T value) -> std::enable_if<someCondition, int>
{
  // this is the function I want to call
}

template <typename... T>
int Function(T...)
{
  // This function should never be called, instead I want
  // a compile-time failure if this is called, because it
  // means the above function wasn't successfully resolved.
}

我想这样做的原因是因为无法正确调用Function()并使用正确的条件会导致数千行编译器错误消息,这些消息对于那些不熟悉这些消息的人来说都不是很有用。代码库。

我不想在static_assert中放置Function的原因是因为我们拥有许多这些功能,而我们有办法通过宏生成Catch-all版本,这将避免不必要的代码库增长,同时产生更多有用的错误消息。

可以这样做吗?

2 个答案:

答案 0 :(得分:19)

根据您对问题的评论,您不希望在此处static_assert

template <typename T>
auto Function(T value) -> std::enable_if<someCondition, int>
{
  // this is the function I want to call
}

...但实际上static_assert 并没有错:

template <typename... T>
struct dependent_false { static constexpr bool value = false; };

template <typename... T>
int Function(T...)
{
  static_assert(dependent_false<T...>::value, "you are passing the wrong arguments!");
}

正如您所正确指出的那样,简单的static_assert(false, "...");会在模板定义时失败。要获得仅在实例化时失败的东西,你需要一个依赖表达式,dependent_false辅助结构是一种简单的方法来获得与类型相关的东西,几乎总是false,但编译器不能假设真正始终为false:编译器不能排除您为某种类型添加部分特化以使dependent_false<...>::value true


回顾这个老问题,可能有一个更简单的答案:将重载标记为已删除。

template <typename T>
auto Function(T value) -> std::enable_if<someCondition, int>
{
    // this is the function I want to call
}

template <typename... T>
int Function(T...) = delete;

这不完全相同,因为这允许呼叫者检查例如良好的形状。 Function(int, int)而不是强制错误,但它更具可读性,并且通常 希望 希望确切的行为不会出现错误,除非实际使用该函数,而不仅仅是引用

答案 1 :(得分:0)

只是在公认的答案上做些扩展:
我们可以另外定义以下内容

template <class... T>
inline constexpr bool dependant_false_v = dependant_false<T...>::value;

当时的用法是

template <typename... T>
int Function(T...)
{
  static_assert(dependent_false_v<T...>, "you are passing the wrong arguments!");
}

看起来更干净的IMO,并且写作时间更短。

使用C ++ 17,我们甚至可以摆脱SFINAE enable_if的限制,并通过constexpr if将所有内容合并到一个函数中:

template <typename T>
auto Function(T value)
{
  if constexpr(someCondition) {
    // Code for your function
  } else {
    static_assert(dependent_false_v<T>, "you are passing the wrong arguments!");
  }
}