Skip to content

Instantly share code, notes, and snippets.

@aguinet
Created May 10, 2016 15:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aguinet/791e98368946b9bc5d3e45ab7a2441f2 to your computer and use it in GitHub Desktop.
Save aguinet/791e98368946b9bc5d3e45ab7a2441f2 to your computer and use it in GitHub Desktop.
Helper templates to easily check whether a function type has the right signature (without std::function)
// Copyright (c) 2016 Adrien Guinet
// Helper templates to easily check whether a function type has the right
// signature (without std::function).
// If you have std::function, simply do
//
// template <class F, class R, class... Args>
// struct has_sign:
// public std::is_convertible<F, std::function<R(Args...)>>
// { };
//
// Any better way to do this is appreciated :)
// You can use it freely as long as the original copyright is mentioned.
#include <string>
#include <type_traits>
#include <functional>
template <class F, bool, class R, class... Args>
struct has_sign_impl;
template <class F, class R, class... Args>
struct has_sign_impl<F, false, R, Args...>
{
using func_type = decltype(&F::operator());
static constexpr bool value =
std::is_convertible<func_type, R(F::*)(Args...)>::value |
std::is_convertible<func_type, R(F::*)(Args...) const>::value;
};
template <class F, class R, class... Args>
struct has_sign_impl<F, true, R, Args...>:
public std::is_convertible<F, R(*)(Args...)>
{ };
template <class F, class R, class... Args>
struct has_sign
{
using func_type = typename std::decay<F>::type;
static constexpr bool value = has_sign_impl<func_type, std::is_pointer<func_type>::value, R, Args...>::value;
};
int test(std::string) { return 0; }
int test2(int i) { return 0; }
struct MyF
{
int operator()(std::string) { return _i; }
int _i;
};
struct MyF2
{
int operator()(int a) const { return a+_i; }
int _i;
};
template <class F>
bool is_ok(F f)
{
return has_sign<F, int, std::string>::value;
}
int main(int argc, char** argv)
{
MyF myf;
MyF2 myf2;
printf("should be ok\n");
printf("%d\n", is_ok(test));
printf("%d\n", is_ok([](std::string) -> int { return 1; }));
printf("%d\n", is_ok(myf));
printf("%d\n", is_ok([argc](std::string) -> int { return argc+1; }));
printf("should fail\n");
printf("%d\n", is_ok(test2));
printf("%d\n", is_ok([](short) -> short { return 1; }));
printf("%d\n", is_ok(myf2));
printf("%d\n", is_ok([argc](short) -> short { return argc+1; }));
}
@serge-sans-paille
Copy link

What about

template<class Pattern, class Candidate>
struct match {
  template<class F>
  static auto check(F*)
    -> decltype(std::function<Pattern>(std::declval<F>()), bool());
  static int check(...);

  static constexpr bool value =
    std::is_same<bool, decltype(check(std::declval<Candidate*>()))>::value;
};

template <class Func>
bool foo(Func F)
{
    static_assert(match<int(std::string), Func>::value, "bad signature");
    return true;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment