简体   繁体   English

C ++验证模板类型的可调用签名

[英]C++ verify callable signature of template type

so let's say I have a generic function like this: 所以我想说我有一个像这样的通用函数:

template<typename TFunc>
void templFunc(TFunc func) {
    func(3, 6);
}

Is there any way at compile time that I can verify the signature of TFunc regardless of whether it's an std::function or lambda or function reference of any kind. 在编译时是否有任何方法可以验证TFunc的签名,无论它是std :: function还是lambda或任何类型的函数引用。 I just want to make sure TFunc is of signature void(int, int) or similar with a static_assert so I can produce a non garbage error message. 我只是想确保TFunc是签名void(int,int)或类似static_assert,所以我可以产生非垃圾错误消息。

So I fiddled around with some of the type_traits stuff, and I think I have something that verifies the entire signature, not just the return value, and allows you to create easy to read static_asserts rather than illegible template errors when the signature doesn't match. 所以我摆弄了一些type_traits的东西,我认为我有一些东西可以验证整个签名,而不仅仅是返回值,并且允许您创建易于读取的static_asserts而不是签名不匹配时难以辨认的模板错误。 Is this a bad solution? 这是一个糟糕的解决方案?

#include <functional>

template<typename, typename, typename = void>
struct is_signature : std::false_type {};

template<typename TFunc, typename Ret, typename... Args>
struct is_signature<TFunc, Ret(Args...),
        typename std::enable_if<
            std::is_convertible<
                TFunc,
                std::function<Ret(Args...)>
            >::value
        >::type
    > : public std::true_type
    {};

// works on both functions and lambda's
void blah(int, int) {
}

template<typename TFunc>
void templFunc(TFunc func) {
    static_assert(is_signature<TFunc, void(int, int)>::value, "Not gonna work! more info follows:");
    func(3, 6);
}

int main() {
    auto b = [](int, int) -> void {
    };

    auto c = [](int) -> void {
    };

    static_assert(is_signature<decltype(b), void(int, int)>::value, "b convertible to a std::function<void(int, int), so this checks out!");
    static_assert(is_signature<decltype(b), void(int)>::value, "b not convertible to a std::function<void(int)>, so this will error in compilation.");
    static_assert(is_signature<decltype(blah), void(int, int)>::value, "blah convertible to a std::function<void(int, int), so this checks out!");
    static_assert(is_signature<decltype(blah), void(int)>::value, "blah not convertible to a std::function<void(int)>, so this will error in compilation.");

    templFunc(b); // <- ok
    templFunc(c); // <- static assertion : not gonna work!
    return 0;
}

You can use: 您可以使用:

template<typename TFunc>
void templFunc(TFunc func) {
   static_assert(std::is_void<decltype(func(0,0))>::value,
                 "Bad template argument. The return type is not void");
   func(3, 6);
}
  1. This will make sure that the return type of the function is void . 这将确保函数的返回类型为void
  2. If the function does not take two argument, it will fail in the call func(3,6); 如果函数没有采用两个参数,它将在调用func(3,6);失败func(3,6); -- twice. - 两次。 Once in the static_assert line and once in the next line. 一旦进入static_assert行,就进入下一行。

  3. The function call will succeed if argument types of int or any other type that an int can be promoted to, converted to, or cast to. 如果int参数类型或int可以被提升,转换为或转换为int任何其他类型,则函数调用将成功。 Making sure that the argument types are int only will need some additional work. 确保参数类型仅为int将需要一些额外的工作。 I am not sure what that entails. 我不确定这是什么意思。

Test program: 测试程序:

#include <type_traits>

template<typename TFunc>
void templFunc(TFunc func) {
   static_assert(std::is_void<decltype(func(0,0))>::value, "Bad template argument. The return type is not void");
   func(3, 6);
}

void foo()
{
}

void bar(int x, int y)
{
}

int baz(int x, int y)
{
   return 0;
}

struct Functor
{
   void operator()(long, long)
   {
   }
};

int main()
{
   templFunc(foo);    // Not OK. Two few arguments
   templFunc(bar);    // OK
   templFunc(baz);    // Not OK. Wrong return type
   templFunc([](int, int) -> void {} );  // OK
   templFunc(Functor());   // OK
}

Something like this works using SFINAE (only if you make the assertion based on a template parameter; not exactly sure why, and I think that would be the most interesting part :)): 这样的东西可以使用SFINAE(只有你根据模板参数进行断言;不完全确定原因,我认为这将是最有趣的部分:)):

#include <type_traits>

template<typename TFunc>
typename std::enable_if<std::is_same<typename std::result_of<TFunc(int, int)>::type, void>::value >::type templFunc(TFunc func)
{
  func(3, 6);
}

template<typename TFunc>
typename std::enable_if<!std::is_same<typename std::result_of<TFunc(int, int)>::type, void>::value >::type templFunc(TFunc func)
{
  static_assert(std::is_same<typename std::result_of<TFunc(int, int)>::type, void>::value, "error; invalid function");
}

auto a = [](int, int) {};
auto b = [](int x, int y) { return x + y; };

int main()
{
    templFunc(b);
    return 0;
}

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM