如何检查模板参数是否为具有给定签名的可调用对象 [英] How to check if template argument is a callable with a given signature

查看:80
本文介绍了如何检查模板参数是否为具有给定签名的可调用对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本上,我要实现的是编译时验证(可能带有很好的错误消息),该注册时可调用(函数,lambda,具有调用运算符的结构)具有正确的签名。示例(要填充 static_assert 的内容):

Basically, what I want to achieve is compile-time verification (with possibly nice error message) that registered callable (either a function, a lambda, a struct with call operator) has correct signature. Example (contents of the static_assert are to be filled):

struct A {
  using Signature = void(int, double);

  template <typename Callable>
  void Register(Callable &&callable) {
    static_assert(/* ... */);
    callback = callable;
  }

  std::function<Signature> callback;
};


推荐答案

大多数答案都集中在基本回答问题上:您可以使用这些类型的值调用给定的函数对象。这与匹配签名不同,因为它允许许多您不希望进行的隐式转换。为了获得更严格的匹配,我们必须做一堆TMP。首先,这个答案是:带有可变参数一部分的调用函数显示如何获取参数的确切类型以及可调用对象的返回类型。代码在此处复制:

Most of the answers are focused on basically answering the question: can you call the given function object with values of these types. This is not the same as matching the signature, as it allows many implicit conversions that you say you don't want. In order to get a more strict match we have to do a bunch of TMP. First, this answer: Call function with part of variadic arguments shows how to get the exact types of the arguments and return type of a callable. Code reproduced here:

template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{};

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
{
    using result_type = ReturnType;
    using arg_tuple = std::tuple<Args...>;
    static constexpr auto arity = sizeof...(Args);
};

template <typename R, typename ... Args>
struct function_traits<R(&)(Args...)>
{
    using result_type = R;
    using arg_tuple = std::tuple<Args...>;
    static constexpr auto arity = sizeof...(Args);
};

这样做,您现在可以在代码中放置一系列静态断言了:

Having done that, you can now put a series of static asserts in your code:

struct A {
  using Signature = void(int, double);

  template <typename Callable>
  void Register(Callable &&callable) {
    using ft = function_traits<Callable>;
    static_assert(std::is_same<int,
        std::decay_t<std::tuple_element_t<0, typename ft::arg_tuple>>>::value, "");
    static_assert(std::is_same<double,
        std::decay_t<std::tuple_element_t<1, typename ft::arg_tuple>>>::value, "");
    static_assert(std::is_same<void,
        std::decay_t<typename ft::result_type>>::value, "");

    callback = callable;
  }

  std::function<Signature> callback;
};

由于按价值传递,这基本上就是您所需要的。如果您通过引用传递,我会在使用其他答案之一的地方添加一个额外的静态断言。大概是松原瑶的答案。这样可以解决一些情况,例如基本类型相同,但是const限定的方向错误。

Since you are passing by value this is basically all you need. If you are passing by reference, I would add an additional static assert where you use one of the other answers; probably songyuanyao's answer. This would take care of cases where for example the base type was the same, but the const qualification went in the wrong direction.

您当然可以使所有这些通用类型 Signature ,而不是做我所做的事情(只需在静态断言中重复这些类型)。这样会更好,但是会为已经不平凡的答案增加甚至更复杂的TMP。如果您觉得可以将它与许多不同的 Signature s一起使用,或者它经常更改,那么可能也值得添加该代码。

You could of course make this all generic over the type Signature, instead of doing what I do (simply repeating the types in the static assert). This would be nicer but it would have added even more complex TMP to an already non-trivial answer; if you feel like you will use this with many different Signatures or that it is changing often it is probably worth adding that code as well.

这是一个实时示例: http://coliru.stacked-crooked.com / a / cee084dce9e8dc09 。特别是我的示例:

Here's a live example: http://coliru.stacked-crooked.com/a/cee084dce9e8dc09. In particular, my example:

void foo(int, double) {}
void foo2(double, double) {}

int main()
{
    A a;
    // compiles
    a.Register([] (int, double) {});
    // doesn't
    //a.Register([] (int, double) { return true; });
    // works
    a.Register(foo);
    // doesn't
    //a.Register(foo2);
}

这篇关于如何检查模板参数是否为具有给定签名的可调用对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆