简体   繁体   English

如果可以使用一组特定参数调用的函数存在,如何在编译时检查?

[英]How to check at compile-time if a function that can be called with a specific set of arguments exists?

This is different from checking if a specific function is defined. 这与检查是否定义了特定功能不同。 Here, for this check to return true , the function has to be defined and passing the arguments of a certain type should result in a valid call. 这里,为了使该检查返回true ,必须定义该函数,并且传递某种类型的参数应该导致有效的调用。

Example: for a function f and an argument of type T && , the check should return true if f is a valid function that accepts—either directly or through implicit conversion—an argument of type T && . 示例:对于函数f和类型为T &&的参数,如果f是直接或通过隐式转换(类型为T &&的参数)接受的有效函数,则检查应返回true

void f(int &) {};

int main(int argc, char **av)
{
    isFunctionCallable<int>(f); // true because `int i; f(i);` is valid.
    isFunctionCallable<int &&>(f); // false because `int i; f(std::move(i));` is invalid.
    return 0;
}

Please note the distinction between “arguments” and “parameters” as explained in this answer . 请注意本答案中解释的“参数”和“参数”之间的区别。

Making use of C++11, this can be done using a mixture of SFINAE, decltype and std::declval . 利用C ++ 11,可以使用SFINAE, decltypestd::declval的混合来完成。

template<typename ...>
struct Bool
{ using type = bool; };

template<typename ... T_Dummies>
using BoolT = typename Bool<T_Dummies ...>::type;


template<typename T>
struct DeclvalType
{
    using type = typename std::conditional<
        std::is_rvalue_reference<T>::value,
        T,
        T &
    >::type;
};

template<typename T>
using DeclvalTypeT = typename DeclvalType<T>::type;


template<typename T>
struct ExtractFunction;

template<typename T_Return, typename ... T_Args>
struct ExtractFunction<T_Return(T_Args ...)>
{ using type = T_Return(T_Args ...); };

template<typename T_Return, typename ... T_Args>
struct ExtractFunction<T_Return(*)(T_Args ...)>
{ using type = T_Return(T_Args ...); };

template<typename T, typename T_Return, typename ... T_Args>
struct ExtractFunction<T_Return(T::*)(T_Args ...)>
{ using type = T_Return(T_Args ...); };

template<typename T, typename T_Return, typename ... T_Args>
struct ExtractFunction<T_Return(T::*)(T_Args ...) const>
{ using type = T_Return(T_Args ...); };

template<typename T>
using ExtractFunctionT = typename ExtractFunction<T>::type;


template<typename ... T, typename T_Function>
constexpr auto
impl(T_Function function) ->
    BoolT<decltype(
        std::declval<ExtractFunctionT<T_Function>>()
            (std::declval<DeclvalTypeT<T>>() ...)
    )>
{ return true; }

template<typename ... T>
constexpr bool
impl(...)
{ return false; }


template<typename ... T, typename T_Function>
constexpr bool
isFunctionCallable(T_Function function)
{ return impl<T ...>(function); }

With the help of some more code (available in this Gist ), it is possible to output tables showing what type of arguments can be passed to what type of parameters. 借助更多代码(在本Gist中可用),可以输出表格,显示可以将哪种类型的参数传递给哪种类型的参数。

using T = Default (empty struct with implicit constructors):

  +--------------------------------+---------------------------------------------------------------------------------------------------------------------------------+
  |                                |                                                                                                                                 |
  |        Function signature      |                                                          Argument type                                                          |
  |                                |                                                                                                                                 |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |                                |  T  |  const T  |   volatile T  |   const volatile T  |  T &  |  const T &  |   volatile T &  |   const volatile T &  |   T &&  |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(T)                   |  x  |     x     |               |                     |   x   |      x      |                 |                       |    x    |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(const T)             |  x  |     x     |               |                     |   x   |      x      |                 |                       |    x    |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(volatile T)          |  x  |     x     |               |                     |   x   |      x      |                 |                       |    x    |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(const volatile T)    |  x  |     x     |               |                     |   x   |      x      |                 |                       |    x    |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(T &)                 |  x  |           |               |                     |   x   |             |                 |                       |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(const T &)           |  x  |     x     |               |                     |   x   |      x      |                 |                       |    x    |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(volatile T &)        |  x  |           |       x       |                     |   x   |             |        x        |                       |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(const volatile T &)  |  x  |     x     |       x       |          x          |   x   |      x      |        x        |           x           |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(T &&)                |     |           |               |                     |       |             |                 |                       |    x    |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+


using T = NonCopiable:

  +--------------------------------+---------------------------------------------------------------------------------------------------------------------------------+
  |                                |                                                                                                                                 |
  |        Function signature      |                                                          Argument type                                                          |
  |                                |                                                                                                                                 |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |                                |  T  |  const T  |   volatile T  |   const volatile T  |  T &  |  const T &  |   volatile T &  |   const volatile T &  |   T &&  |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(T)                   |     |           |               |                     |       |             |                 |                       |    x    |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(const T)             |     |           |               |                     |       |             |                 |                       |    x    |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(volatile T)          |     |           |               |                     |       |             |                 |                       |    x    |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(const volatile T)    |     |           |               |                     |       |             |                 |                       |    x    |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(T &)                 |  x  |           |               |                     |   x   |             |                 |                       |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(const T &)           |  x  |     x     |               |                     |   x   |      x      |                 |                       |    x    |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(volatile T &)        |  x  |           |       x       |                     |   x   |             |        x        |                       |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(const volatile T &)  |  x  |     x     |       x       |          x          |   x   |      x      |        x        |           x           |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(T &&)                |     |           |               |                     |       |             |                 |                       |    x    |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+


using T = NonMovable:

  +--------------------------------+---------------------------------------------------------------------------------------------------------------------------------+
  |                                |                                                                                                                                 |
  |        Function signature      |                                                          Argument type                                                          |
  |                                |                                                                                                                                 |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |                                |  T  |  const T  |   volatile T  |   const volatile T  |  T &  |  const T &  |   volatile T &  |   const volatile T &  |   T &&  |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(T)                   |  x  |     x     |               |                     |   x   |      x      |                 |                       |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(const T)             |  x  |     x     |               |                     |   x   |      x      |                 |                       |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(volatile T)          |  x  |     x     |               |                     |   x   |      x      |                 |                       |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(const volatile T)    |  x  |     x     |               |                     |   x   |      x      |                 |                       |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(T &)                 |  x  |           |               |                     |   x   |             |                 |                       |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(const T &)           |  x  |     x     |               |                     |   x   |      x      |                 |                       |    x    |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(volatile T &)        |  x  |           |       x       |                     |   x   |             |        x        |                       |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(const volatile T &)  |  x  |     x     |       x       |          x          |   x   |      x      |        x        |           x           |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(T &&)                |     |           |               |                     |       |             |                 |                       |    x    |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+


using T = NonCopiableNonMovable:

  +--------------------------------+---------------------------------------------------------------------------------------------------------------------------------+
  |                                |                                                                                                                                 |
  |        Function signature      |                                                          Argument type                                                          |
  |                                |                                                                                                                                 |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |                                |  T  |  const T  |   volatile T  |   const volatile T  |  T &  |  const T &  |   volatile T &  |   const volatile T &  |   T &&  |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(T)                   |     |           |               |                     |       |             |                 |                       |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(const T)             |     |           |               |                     |       |             |                 |                       |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(volatile T)          |     |           |               |                     |       |             |                 |                       |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(const volatile T)    |     |           |               |                     |       |             |                 |                       |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(T &)                 |  x  |           |               |                     |   x   |             |                 |                       |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(const T &)           |  x  |     x     |               |                     |   x   |      x      |                 |                       |    x    |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(volatile T &)        |  x  |           |       x       |                     |   x   |             |        x        |                       |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(const volatile T &)  |  x  |     x     |       x       |          x          |   x   |      x      |        x        |           x           |         |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
  |  function(T &&)                |     |           |               |                     |       |             |                 |                       |    x    |
  +--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+

We can for example deduce from these tables that an argument of type T can't be passed to a function that takes T && as parameter. 例如,我们可以从这些表中推断出类型T的参数不能传递给以T &&作为参数的函数。 Or that function(T &&) only accepts arguments of type T && . 或者该function(T &&)只接受T &&类型的参数。

Note how deleting the copy and/or the move constructor reduce the possibilities since the arguments can't be converted implicitly anymore. 请注意删除副本和/或移动构造函数如何减少可能性,因为参数不能再隐式转换。

Edit: 编辑:

Added support for member functions, thanks to @hvd. 由于@hvd,增加了对成员函数的支持。

#define overload_set(F)\
  struct { auto operator()(auto&&...args)const\
    ->decltype(F(std::forward<decltype(args)>(args)...))\
     { return (F(std::forward<decltype(args)>(args)...)); }\
  }

this takes a token F and generates an overload set type for F . 这需要一个令牌F并为F生成一个过载集类型。

It is not quite perfect: it only does perfect forwarding with SFINAE tests. 它并不完美:它只能通过SFINAE测试完美转发。 But it is close. 但它很接近。

We then use this: 然后我们用这个:

template<class T,class=void>struct can_invoke:std::false_type{};
template<class F,class...Args>
struct can_invoke<F(Args...),
  decltype(void(
    std::declval<F>()(std::declval<Args>()...)
  ))
>:std::true_type{};

Mixing them we get: 混合它们我们得到:

typedef overload_set(Foo) Foo_overloads;
std::cout << can_invoke<Foo_overloads(int, int) >::value<<"\n";

will print 1 if Foo(3,2) works. 如果Foo(3,2)有效,将打印1 As noted, this is limited by failures of perfect forwarding. 如上所述,这受到完美转发失败的限制。

You can also pass Foo_overloads{} to functions expecting a function object, and it will dispatch at the call site instead of doing it when you pass the function object. 您还可以将Foo_overloads{}传递给期望函数对象的函数,并且它将在调用站点进行调度,而不是在传递函数对象时进行调度。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如果调用 function 的特定重载,如何引发编译时错误? - How to provoke a compile-time error if a specific overload of a function is called? 如何检查在编译时是否调用了模板化方法? - How can I check if a templated method was called at compile-time? c ++编译时检查函数参数 - c++ compile-time check function arguments C ++编译时检查是否可以使用某种类型的参数调用重载函数 - C++ Compile-time check that an overloaded function can be called with a certain type of argument 如何在编译时检查类是否具有继承的函数? - How to check if a class has an inherited function at compile-time? 如何向特定功能添加编译时元数据/行为 - how to add compile-time metadata/behavior to specific function 我可以在编译时检测到编译时常量的“函数参数” - Can I detect at compile time “function arguments” that are compile-time constants 如何在编译时调试模板参数? - How to debug template arguments at compile-time? 使用带有参数类型的可变参数模板在c ++中获取函数在编译时的参数个数 - Getting the number of arguments to a function at compile-time using variadic templates with argument type check in c++ 如何在编译时检查函数是否被调用 - How to check at compile time if a function is called
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM