#pragma once

template <class Function>
struct strip_signature;

template <class Return, class Class, class... Args>
struct strip_signature<Return (Class::*)(Args...)>
{
	using type = Return(Args...);
};

template <class Return, class Class, class... Args>
struct strip_signature<Return (Class::*)(Args...) const>
{
	using type = Return(Args...);
};

template <class Return, class Class, class... Args>
struct strip_signature<Return (Class::*)(Args...) volatile>
{
	using type = Return(Args...);
};

template <class Return, class Class, class... Args>
struct strip_signature<Return (Class::*)(Args...) const volatile>
{
	using type = Return(Args...);
};

template <class Return, class Class, class... Args>
struct strip_signature<Return (Class::*)(Args...) &>
{
	using type = Return(Args...);
};

template <class Return, class Class, class... Args>
struct strip_signature<Return (Class::*)(Args...) const &>
{
	using type = Return(Args...);
};

template <class Return, class Class, class... Args>
struct strip_signature<Return (Class::*)(Args...) volatile &>
{
	using type = Return(Args...);
};

template <class Return, class Class, class... Args>
struct strip_signature<Return (Class::*)(Args...) const volatile &>
{
	using type = Return(Args...);
};

template <class Return, class Class, class... Args>
struct strip_signature<Return (Class::*)(Args...) noexcept>
{
	using type = Return(Args...);
};

template <class Return, class Class, class... Args>
struct strip_signature<Return (Class::*)(Args...) const noexcept>
{
	using type = Return(Args...);
};

template <class Return, class Class, class... Args>
struct strip_signature<Return (Class::*)(Args...) volatile noexcept>
{
	using type = Return(Args...);
};

template <class Return, class Class, class... Args>
struct strip_signature<Return (Class::*)(Args...) const volatile noexcept>
{
	using type = Return(Args...);
};

template <class Return, class Class, class... Args>
struct strip_signature<Return (Class::*)(Args...) &noexcept>
{
	using type = Return(Args...);
};

template <class Return, class Class, class... Args>
struct strip_signature<Return (Class::*)(Args...) const &noexcept>
{
	using type = Return(Args...);
};

template <class Return, class Class, class... Args>
struct strip_signature<Return (Class::*)(Args...) volatile &noexcept>
{
	using type = Return(Args...);
};

template <class Return, class Class, class... Args>
struct strip_signature<Return (Class::*)(Args...) const volatile &noexcept>
{
	using type = Return(Args...);
};

template <class Function>
using strip_signature_t = typename strip_signature<Function>::type;