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

后端 未结 2 1142
独厮守ぢ
独厮守ぢ 2021-01-01 05:18

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

2条回答
  •  离开以前
    2021-01-01 05:56

    Making use of C++11, this can be done using a mixture of SFINAE, decltype and std::declval.

    template
    struct Bool
    { using type = bool; };
    
    template
    using BoolT = typename Bool::type;
    
    
    template
    struct DeclvalType
    {
        using type = typename std::conditional<
            std::is_rvalue_reference::value,
            T,
            T &
        >::type;
    };
    
    template
    using DeclvalTypeT = typename DeclvalType::type;
    
    
    template
    struct ExtractFunction;
    
    template
    struct ExtractFunction
    { using type = T_Return(T_Args ...); };
    
    template
    struct ExtractFunction
    { using type = T_Return(T_Args ...); };
    
    template
    struct ExtractFunction
    { using type = T_Return(T_Args ...); };
    
    template
    struct ExtractFunction
    { using type = T_Return(T_Args ...); };
    
    template
    using ExtractFunctionT = typename ExtractFunction::type;
    
    
    template
    constexpr auto
    impl(T_Function function) ->
        BoolT>()
                (std::declval>() ...)
        )>
    { return true; }
    
    template
    constexpr bool
    impl(...)
    { return false; }
    
    
    template
    constexpr bool
    isFunctionCallable(T_Function function)
    { return impl(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.

    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. Or that function(T &&) only accepts arguments of type 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.

提交回复
热议问题