Skip to content

Instantly share code, notes, and snippets.

@Sunday111
Created August 24, 2022 14:39
Show Gist options
  • Save Sunday111/e6b52180ba6aab726739c7728a603aba to your computer and use it in GitHub Desktop.
Save Sunday111/e6b52180ba6aab726739c7728a603aba to your computer and use it in GitHub Desktop.
Get function or method information by type
#pragma once
#include <type_traits>
#include <tuple>
template<typename T>
struct Signature;
// function
template<typename Ret_, typename... Args_>
struct Signature<Ret_(*)(Args_...)> {
using Ret = Ret_;
using Class = void;
using Args = std::tuple<Args_...>;
static constexpr bool Const = false;
static constexpr bool Noexcept = false;
static constexpr bool Volatile = false;
static constexpr bool Pure = true;
static constexpr bool LRef = false;
static constexpr bool RRef = false;
};
// noexcept function
template<typename Ret_, typename... Args_>
struct Signature<Ret_(*)(Args_...) noexcept> : Signature<Ret_(*)(Args_...)> {
static constexpr bool Noexcept = true;
};
// method
template<typename Ret_, typename Class_, typename... Args_>
struct Signature<Ret_(Class_::*)(Args_...)> : Signature<Ret_(*)(Args_...)> {
using Class = Class_;
static constexpr bool Pure = false;
};
#ifndef SIGNATURE_METHOD_SPECIALIZATION
#define SIGNATURE_METHOD_SPECIALIZATION(qualifiers)\
template<typename Ret_, typename Class_, typename... Args_>\
struct Signature<Ret_(Class_::*)(Args_...) qualifiers> : Signature<Ret_(Class_::*)(Args_...)>
#else
static_assert(false, "Name collision with test macro");
#endif
SIGNATURE_METHOD_SPECIALIZATION(&) {
static constexpr bool LRef = true;
};
SIGNATURE_METHOD_SPECIALIZATION(&&) {
static constexpr bool RRef = true;
};
SIGNATURE_METHOD_SPECIALIZATION(const) {
static constexpr bool Const = true;
};
SIGNATURE_METHOD_SPECIALIZATION(const &) {
static constexpr bool Const = true;
static constexpr bool LRef = true;
};
SIGNATURE_METHOD_SPECIALIZATION(const &&) {
static constexpr bool Const = true;
static constexpr bool RRef = true;
};
SIGNATURE_METHOD_SPECIALIZATION(noexcept) {
static constexpr bool Noexcept = true;
};
SIGNATURE_METHOD_SPECIALIZATION(& noexcept) {
static constexpr bool Noexcept = true;
static constexpr bool LRef = true;
};
SIGNATURE_METHOD_SPECIALIZATION(&& noexcept) {
static constexpr bool Noexcept = true;
static constexpr bool RRef = true;
};
SIGNATURE_METHOD_SPECIALIZATION(volatile) {
static constexpr bool Volatile = true;
};
SIGNATURE_METHOD_SPECIALIZATION(volatile &) {
static constexpr bool Volatile = true;
static constexpr bool LRef = true;
};
SIGNATURE_METHOD_SPECIALIZATION(volatile &&) {
static constexpr bool Volatile = true;
static constexpr bool RRef = true;
};
SIGNATURE_METHOD_SPECIALIZATION(const noexcept) {
static constexpr bool Const = true;
static constexpr bool Noexcept = true;
};
SIGNATURE_METHOD_SPECIALIZATION(const & noexcept) {
static constexpr bool Const = true;
static constexpr bool Noexcept = true;
static constexpr bool LRef = true;
};
SIGNATURE_METHOD_SPECIALIZATION(const && noexcept) {
static constexpr bool Const = true;
static constexpr bool Noexcept = true;
static constexpr bool RRef = true;
};
SIGNATURE_METHOD_SPECIALIZATION(const volatile) {
static constexpr bool Const = true;
static constexpr bool Volatile = true;
};
SIGNATURE_METHOD_SPECIALIZATION(const volatile &) {
static constexpr bool Const = true;
static constexpr bool Volatile = true;
static constexpr bool LRef = true;
};
SIGNATURE_METHOD_SPECIALIZATION(const volatile &&) {
static constexpr bool Const = true;
static constexpr bool Volatile = true;
static constexpr bool RRef = true;
};
SIGNATURE_METHOD_SPECIALIZATION(volatile noexcept) {
static constexpr bool Volatile = true;
static constexpr bool Noexcept = true;
};
SIGNATURE_METHOD_SPECIALIZATION(volatile & noexcept) {
static constexpr bool Volatile = true;
static constexpr bool Noexcept = true;
static constexpr bool LRef = true;
};
SIGNATURE_METHOD_SPECIALIZATION(volatile && noexcept) {
static constexpr bool Volatile = true;
static constexpr bool Noexcept = true;
static constexpr bool RRef = true;
};
SIGNATURE_METHOD_SPECIALIZATION(const volatile noexcept) {
static constexpr bool Const = true;
static constexpr bool Volatile = true;
static constexpr bool Noexcept = true;
};
SIGNATURE_METHOD_SPECIALIZATION(const volatile & noexcept) {
static constexpr bool Const = true;
static constexpr bool Volatile = true;
static constexpr bool Noexcept = true;
static constexpr bool LRef = true;
};
SIGNATURE_METHOD_SPECIALIZATION(const volatile && noexcept) {
static constexpr bool Const = true;
static constexpr bool Volatile = true;
static constexpr bool Noexcept = true;
static constexpr bool RRef = true;
};
#undef SIGNATURE_METHOD_SPECIALIZATION
#ifndef SIGNATURE_TEST_METHOD
#define SIGNATURE_TEST_METHOD(pre_qualifiers, name, qualifiers)\
pre_qualifiers int name(float, double) qualifiers { return 42; }
#else
static_assert(false, "Name collision with test macro");
#endif
#include "signature.hpp"
struct Foo {
SIGNATURE_TEST_METHOD(, method,);
SIGNATURE_TEST_METHOD(, lref_method, &);
SIGNATURE_TEST_METHOD(, rref_method, &&);
SIGNATURE_TEST_METHOD(, const_method, const);
SIGNATURE_TEST_METHOD(, const_lref_method, const &);
SIGNATURE_TEST_METHOD(, const_rref_method, const &&);
SIGNATURE_TEST_METHOD(, const_noexcept_method, const noexcept);
SIGNATURE_TEST_METHOD(, const_lref_noexcept_method, const & noexcept);
SIGNATURE_TEST_METHOD(, const_rref_noexcept_method, const && noexcept);
SIGNATURE_TEST_METHOD(, const_volatile_method, const volatile);
SIGNATURE_TEST_METHOD(, const_volatile_lref_method, const volatile &);
SIGNATURE_TEST_METHOD(, const_volatile_rref_method, const volatile &&);
SIGNATURE_TEST_METHOD(, volatile_method, volatile);
SIGNATURE_TEST_METHOD(, volatile_lref_method, volatile &);
SIGNATURE_TEST_METHOD(, volatile_rref_method, volatile &&);
SIGNATURE_TEST_METHOD(, noexcept_method, noexcept);
SIGNATURE_TEST_METHOD(, lref_noexcept_method, & noexcept);
SIGNATURE_TEST_METHOD(, rref_noexcept_method, && noexcept);
SIGNATURE_TEST_METHOD(, volatile_noexcept_method, volatile noexcept);
SIGNATURE_TEST_METHOD(, volatile_lref_noexcept_method, volatile & noexcept);
SIGNATURE_TEST_METHOD(, volatile_rref_noexcept_method, volatile && noexcept);
SIGNATURE_TEST_METHOD(, const_volatile_noexcept_method, const volatile noexcept);
SIGNATURE_TEST_METHOD(, const_volatile_lref_noexcept_method, const volatile & noexcept);
SIGNATURE_TEST_METHOD(, const_volatile_rref_noexcept_method, const volatile && noexcept);
SIGNATURE_TEST_METHOD(static, static_method,);
SIGNATURE_TEST_METHOD(static, static_noexcept_method,noexcept);
};
#undef SIGNATURE_TEST_METHOD
#ifndef SIGNATURE_TEST
#define SIGNATURE_TEST(name, is_const, is_noexcept, is_volatile, is_pure, is_lref, is_rref) \
namespace _##name##_test { \
using Type = Signature<decltype(&Foo::name)>; \
static_assert(std::is_same_v<typename Type::Ret, int>); \
static_assert(is_pure || std::is_same_v<typename Type::Class, Foo>); \
static_assert(std::is_same_v<typename Type::Args, std::tuple<float, double>>); \
static_assert(is_const == Type::Const); \
static_assert(is_noexcept == Type::Noexcept); \
static_assert(is_volatile == Type::Volatile); \
static_assert(is_pure == Type::Pure); \
static_assert(is_lref == Type::LRef); \
static_assert(is_rref == Type::RRef); \
}
#else
static_assert(false, "Name collision with test macro");
#endif
// static functions
SIGNATURE_TEST(static_method, false, false, false, true, false, false);
SIGNATURE_TEST(static_noexcept_method, false, true, false, true, false, false);
// methods const noexcept volat pure lref rref
SIGNATURE_TEST(method, false, false, false, false, false, false);
SIGNATURE_TEST(lref_method, false, false, false, false, true, false);
SIGNATURE_TEST(rref_method, false, false, false, false, false, true);
SIGNATURE_TEST(const_method, true, false, false, false, false, false);
SIGNATURE_TEST(const_lref_method, true, false, false, false, true, false);
SIGNATURE_TEST(const_rref_method, true, false, false, false, false, true);
SIGNATURE_TEST(noexcept_method, false, true, false, false, false, false);
SIGNATURE_TEST(lref_noexcept_method, false, true, false, false, true, false);
SIGNATURE_TEST(rref_noexcept_method, false, true, false, false, false, true);
SIGNATURE_TEST(volatile_method, false, false, true, false, false, false);
SIGNATURE_TEST(volatile_lref_method, false, false, true, false, true, false);
SIGNATURE_TEST(volatile_rref_method, false, false, true, false, false, true);
SIGNATURE_TEST(const_noexcept_method, true, true, false, false, false, false);
SIGNATURE_TEST(const_lref_noexcept_method, true, true, false, false, true, false);
SIGNATURE_TEST(const_rref_noexcept_method, true, true, false, false, false, true);
SIGNATURE_TEST(const_volatile_method, true, false, true, false, false, false);
SIGNATURE_TEST(const_volatile_lref_method, true, false, true, false, true, false);
SIGNATURE_TEST(const_volatile_rref_method, true, false, true, false, false, true);
SIGNATURE_TEST(volatile_noexcept_method, false, true, true, false, false, false);
SIGNATURE_TEST(volatile_lref_noexcept_method, false, true, true, false, true, false);
SIGNATURE_TEST(volatile_rref_noexcept_method, false, true, true, false, false, true);
SIGNATURE_TEST(const_volatile_noexcept_method, true, true, true, false, false, false);
SIGNATURE_TEST(const_volatile_lref_noexcept_method, true, true, true, false, true, false);
SIGNATURE_TEST(const_volatile_rref_noexcept_method, true, true, true, false, false, true);
#undef SIGNATURE_TEST
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment