Suppose we have:
template<typename F, typename T1, typename T2>
void my_magic_method(F func, T1 t1, T2 t2)
{
if (???)
func(t1);
else
func(t1,t2);
}
What can help me to determine:
Number of arguments
Maybe types of each argument
Type of return value
I cant use variadic templates because of MSVS 2010...
UPDATE
My first solution:
template<typename F>
auto my_magic_func(F f) -> decltype(f(1))
{
return f(1);
}
template<typename F>
auto my_magic_func(F f, void * fake = NULL) -> decltype(f(2,3))
{
return f(2,3);
}
int main()
{
auto x1 = my_magic_func([](int a){ return a+100; });
auto x2 = my_magic_func([](int a, int b){ return a*b; });
// x1 == 1+100
// x2 == 2*3
}
Thats my way of function-type overloading.
It works, but maybe a better solutuion?
Not exactly what you asked for, but if I understand your intent correctly, in VC++ 2010 it's possible (but ugly) via simple overloading based on arity:
#include <utility>
#include <string>
#include <iostream>
template<typename F, typename T1>
auto my_magic_method(F&& func, T1&& t1) ->
decltype(std::forward<F>(func)(std::forward<T1>(t1)))
{
return std::forward<F>(func)(std::forward<T1>(t1));
}
template<typename F, typename T1, typename T2>
auto my_magic_method(F&& func, T1&& t1, T2&& t2) ->
decltype(std::forward<F>(func)(std::forward<T1>(t1), std::forward<T2>(t2)))
{
return std::forward<F>(func)(std::forward<T1>(t1), std::forward<T2>(t2));
}
struct string_to_float_functor
{
float operator ()(std::string const& s) const
{
return std::stof(s);
}
};
int main()
{
auto a = my_magic_method([](std::string const& x) { return x + x; }, "foo");
auto b = my_magic_method([](double x, int y) { return x * y; }, 21.5, 3);
auto c = my_magic_method(string_to_float_functor(), "3.14159265");
std::cout << a << '\n' << b << '\n' << c << '\n';
}
This supports unary and binary functors – continue the pattern and add overloads for other arities as needed.
Here's a few approaches; all assume C++11. Tested on clang++ 3.2 with -std=c++11.
//Taking a function pointer argument (template types inferred)
template <typename ret, typename ... Args>
constexpr int arg_count(ret (*f)(Args...)) {
return sizeof...(Args);
}
//Taking a function type (or related) directly
template <typename T>
struct ArgCount {
static const int value = 0;
};
template <typename Ret, typename ... Args>
struct ArgCount<Ret(Args...)> {
static const int value = sizeof...(Args);
};
template <typename Ret, typename ... Args>
struct ArgCount<Ret(*)(Args...)> {
static const int value = sizeof...(Args);
};
template <typename Ret, typename ... Args>
struct ArgCount<Ret(&)(Args...)> {
static const int value = sizeof...(Args);
};
//Using the latter for dispatch
template <int N>
struct helper {
template<typename F, typename T1, typename T2>
static void call(F func, T1 t1, T2 t2);
};
template <>
struct helper<1> {
template<typename F, typename T1, typename T2>
static void call(F func, T1 t1, T2 t2) {
func(t1);
}
};
template <>
struct helper<2> {
template<typename F, typename T1, typename T2>
static void call(F func, T1 t1, T2 t2) {
func(t1, t2);
}
};
template<typename F, typename T1, typename T2>
void my_magic_method(F func, T1 t1, T2 t2)
{
helper<ArgCount<F>::value>::call(func, t1, t2);
}
//Testing
#include <cstdio>
void a(int a, int b) { printf("%i\n", a + b); }
void b(int x) { printf("%i\n", x); }
int main() {
printf("%i %i\n", arg_count(a), arg_count(b));
printf("%i %i\n", ArgCount<decltype(a)>::value, ArgCount<decltype(b)>::value);
my_magic_method(a, 1, 2);
my_magic_method(b, 1, 2);
}
Related
How can I specialized a template function to return true if objects belong to certain templates/classes and false for other templates/classes
no classes have virtual functions.
I have a template:
template<typename t1, typename t2, bool a> struct DynamicData{...}
which I want to do special processing, or any class derived from that template.
in the following example I have a specialization of DynamicData<>: DynamicDataSym<> for which I did a specialization of is_dynamic<>, but because DynamicDataSym<> is derived from DynamicData<> I wonder if there is a way that anytime I create a new derive class from DynamicData<> I can have is_dynamic<> work automatically.
the design with the templates cannot be changed, and no virtual methods are allowed!
Also working with C++17, so c++20 & C++23 out of the equation!
class ClrngAssetBuff
{
int name1 {};
public:
int GetName();
};
template<typename t1, typename t2, bool a>
struct DynamicData
{
t1 m1;
t2 m2;
};
template<typename t1, typename t2, int sym>
struct DynamicDataSym : DynamicData<t1, t2, true>
{
int some() { return sym; }
};
template<typename t1>
struct DynamicDataSym2 : DynamicData<t1, float, true>
{
float some() { return 1.0f; }
};
template<typename T>
constexpr bool is_dynamic(const T& t)
{
return false;
}
template<typename T1, typename T2, bool a>
constexpr bool is_dynamic(const DynamicData<T1, T2, a>& t)
{
return true;
}
template<typename T1, typename T2, int a>
constexpr bool is_dynamic(const DynamicDataSym<T1, T2, a>& t)
{
return true;
}
template<typename T>
constexpr bool is_dynamic2()
{
return is_dynamic<>(T {});
}
template<typename T> void DoDynamicInfo(const T& t);
template<typename T> void ExecuteMessage(const T& t);
template<typename T>
void ProcessMessage(const T& t)
{
if (is_dynamic2<T>())
DoDynamicInfo(t);
ExecuteMessage(t);
}
int main(int argc, char** argv)
{
ClrngAssetBuff msg1;
ProcessMessage(msg1);
DynamicData<int, double, false> msg2;
ProcessMessage(msg2);
DynamicDataSym<int, int, 10> msg3;
ProcessMessage(msg3);
DynamicDataSym2<long long> msg4;
ProcessMessage(msg4); // oops should call DoDynamicInfo(msg4)
}
If I correctly understand what do you want... you're looking for something as follows
template <typename T1, typename T2, bool B>
std::true_type is_dynamic_helper (DynamicData<T1, T2, B> *);
std::false_type is_dynamic_helper (...);
template <typename T>
constexpr auto is_dynamic
= decltype(is_dynamic_helper(std::declval<T*>()))::value;
that is a template variable (available starting from C++14, so is good for a C++17 solution) that is true when a pointer of the template T type can be converted to a DynamicData<T1, T2, B> (for generics T1, T2 types and a generic boolean B value), false otherwise.
So is_dynamic is true when T is a DynamicData or derive from a DynamicData. Unfortunately this doesn't works when T derive from two or more DynamicData classes.
Observe that I've made is_dynamic a constexpr variable, so you can use is constexpr, if you want, inside ProcessMessage()
template <typename T>
void ProcessMessage(const T& t)
{
if constexpr ( is_dynamic<T> )
DoDynamicInfo(t);
ExecuteMessage(t);
}
The following is a full compiling C++17 example
#include <iostream>
class ClrngAssetBuff
{
int name1 {};
public:
int GetName();
};
template <typename t1, typename t2, bool a>
struct DynamicData
{ t1 m1; t2 m2; };
template <typename t1, typename t2, int sym>
struct DynamicDataSym : DynamicData<t1, t2, true>
{ int some() { return sym; } };
template <typename t1>
struct DynamicDataSym2 : DynamicData<t1, float, true>
{ float some() { return 1.0f; } };
template <typename T>
void DoDynamicInfo(const T& t)
{ std::cout << "Do Dynamic Info" << std::endl; }
template <typename T>
void ExecuteMessage(const T& t)
{ std::cout << "Execute Message" << std::endl; }
template <typename T1, typename T2, bool B>
std::true_type is_dynamic_helper (DynamicData<T1, T2, B> *);
std::false_type is_dynamic_helper (...);
template <typename T>
constexpr auto is_dynamic
= decltype(is_dynamic_helper(std::declval<T*>()))::value;
template <typename T>
void ProcessMessage(const T& t)
{
if constexpr ( is_dynamic<T> )
DoDynamicInfo(t);
ExecuteMessage(t);
}
int main()
{
ClrngAssetBuff msg1;
std::cout << "---- msg1" << std::endl;
ProcessMessage(msg1);
DynamicData<int, double, false> msg2;
std::cout << "---- msg2" << std::endl;
ProcessMessage(msg2);
DynamicDataSym<int, int, 10> msg3;
std::cout << "---- msg3" << std::endl;
ProcessMessage(msg3);
DynamicDataSym2<long long> msg4;
std::cout << "---- msg4" << std::endl;
ProcessMessage(msg4); // now call DoDynamicInfo(msg4)
}
I'm trying to implement something of the form
template<typename ...args>
void func(int l, args... arg, int r){
}
I could use
template<typename ...args>
void func(int l, int r, args... arg){
}
but it would make it far more unintuitive to use.
The function itself is
template<typename ...TA, enable_if_t<sizeof...(TA) == 2 * (d - 1), int> = 0>
void upd(int u1, TA... args, T val){
u1 += n;
while(u1){
t[u1].upd(args..., val);
u1 >>= 1;
}
}
d seems fixed, so it is not really variadic.
You can then have specializations (up to a certain limit)
template <std::size_t d>
struct S;
template <>
struct S<0>
{
void upd(int u1, T val){
u1 += n;
while(u1){
t[u1].upd(val);
u1 >>= 1;
}
}
};
template <>
struct S<1>
{
template <typename T1, typename T2>
void upd(int u1, T1 t1, T2 t2, T val){
u1 += n;
while(u1){
t[u1].upd(T1, t2, val);
u1 >>= 1;
}
}
};
//...
// struct S<2>
// ...
// void upd(int u1, T1 t1, T2 t2, T3 t3, T4 t4, T val){
// ...
If the types T1, TN are fixed (assuming SomeType), one possibility is to use std::index_sequence instead of d
template <std::size_t, typename T>
using always_t = T;
template <typename Seq>
struct S_impl;
template <std::size_t... Is>
struct S_impl<std::index_sequence<Is...>>
{
void upd(int u1, always_t<Is, SomeType>... args, T val){
u1 += n;
while(u1) {
t[u1].upd(args..., val);
u1 >>= 1;
}
}
};
template <std::size_t d>
using S = S_impl<std::make_index_sequence<d>>;
Else, you can use tuple or reordering argument for implementation, and provide wrapper for the interface:
template<std::size_t... Is, typename Tuple>
auto extract(std::index_sequence<Is...>, Tuple t)
{
return std::tie(std::get<Is>(t)...);
}
template <typename ...Ts, enable_if_t<sizeof...(Ts) == 2 * (d - 1), int> = 0>
void upd_impl(int u1, std::tuple<Ts...> tup, T val) {
u1 += n;
while(u1){
std::apply([&](auto&&... args){
t[u1].upd(args..., val);
u1 >>= 1;
}, tup
}
}
template <typename ...Ts, enable_if_t<sizeof...(Ts) == 1 + 2 * (d - 1), int> = 0>
void upd(int u1, Ts... args) {
upd_impl(u1,
extract(std::make_index_sequence<sizeof...(Ts) - 1>(),
std::tie(args...)),
std::get<sizeof...(Ts) - 1>(std::tie(args...)));
}
Currently I'm looking for some way to get the parameter types of an overloaded member function by argument count and instance type.
In my case we know the name, the return type (void) and the argument count.
In addition there can't be a second overload with the same argument count and the functions are never cv nor ref qualified.
A sample:
#include <tuple>
#include <type_traits>
#include <iostream>
class TupleLikeType{
public:
void Deconstruct(int& a, char& b){
a = 12;
b = 'A';
}
void Deconstruct(int& a, char& b, bool& c){
Deconstruct(a, b);
c = true;
}
};
template<typename Type, std::size_t ArgCount>
class TupleDeconstructTypes{
public:
using type =
//to implement
std::conditional_t<ArgCount == 2,
std::tuple<int&, char&>, std::tuple<int&, char&, bool&>
>
//to implement end
;
};
template<typename T>
class DeconstructAdapter
{
private:
T& obj;
public:
template<
typename DepT = T
, typename... Args
>
constexpr void operator()(Args&&... args)
{
return obj.Deconstruct(std::forward<Args>(args)...);
}
public:
constexpr DeconstructAdapter(T& toDeconstruct) : obj(toDeconstruct)
{
}
};
template<typename Tuple>
class TupleWithOutRefs{};
template<template <typename...> typename Tuple, typename... T>
class TupleWithOutRefs<Tuple<T...>>{
public:
using type = Tuple<std::remove_reference_t<T>...>;
};
template<
std::size_t ArgCount
,typename T
,typename Args = typename TupleDeconstructTypes<T, ArgCount>::type
,typename TempTuple = typename TupleWithOutRefs<Args>::type
>
auto CreateTuple(T& t){
auto adapter = DeconstructAdapter(t);
TempTuple result{};
//std::apply calls std::invoke
//during this call all out-references are bound to our allocated stack memory
std::apply(adapter, result);
return result;
}
int main(){
//usage
static_assert(std::is_same_v<
TupleDeconstructTypes<TupleLikeType, 2>::type,
std::tuple<int&, char&>
>);
TupleLikeType t;
auto tuple = CreateTuple<2>(t);
std::cout << std::get<0>(tuple);
}
Do you have any idea to solve this in a generic way?
With limited number, you can do something like:
template <std::size_t Size>
struct helper;
template <>
struct helper<0>
{
template <typename C>
std::tuple<> operator() (void (C::*) ()) const;
};
template <>
struct helper<1>
{
template <typename C, typename T1>
std::tuple<T1> operator() (void (C::*) (T1)) const;
};
template <>
struct helper<2>
{
template <typename C, typename T1, typename T2>
std::tuple<T1, T2> operator() (void (C::*) (T1, T2)) const;
};
template <>
struct helper<3>
{
template <typename C, typename T1, typename T2, typename T3>
std::tuple<T1, T2, T3> operator() (void (C::*) (T1, T2, T3)) const;
};
// ...
template<typename Type, std::size_t ArgCount>
using TupleDeconstructTypes = decltype(helper<ArgCount>{}(&Type::Deconstruct));
Demo
Suppose I have a function like this
template <typename... FunctionList>
void call_all (int i, float f, const FunctionList... function_list);
template <>
void call_all (int, float)
{
}
I want to specialize it something like this:
template <typename HasIntArgument, typename... FL>
void call_all (int i, float f, const HasIntArgument & hia, const FL... list)
{
hia (i);
call_all (i, f, list...);
}
template <typename HasFloatArgument, typename... FL>
void call_all (int i, float f, const HasFloatArgument & hfa, const FL... list)
{
hfa (f);
call_all (i, f, list...);
}
In words, I want this function to, for each function-like object in function_list, determine whether it is callable with signature void(int) or void(float). (Nothing in this list will be callable with more than one signature.)
I want this to work with raw function pointers, lambdas, or anything with a suitable operator().
Can I write a suitable specialization directly, or do I have to do weird stuff with traits classes and SFINAE?
You might do something like:
#if 0 // C++17
template <typename F>
void dispatch(F func, int i, float f)
{
if constexpr (has_int_argument<F>::value) {
func(i);
} else {
func(f);
}
}
#else // C++11
template <typename F>
typename std::enable_if<has_int_argument<F>::value>::type
dispatch(F func, int i, float)
{
func(i);
}
template <typename F>
typename std::enable_if<!has_int_argument<F>::value>::type
dispatch(F func, int, float f)
{
func(f);
}
#endif
template <typename... Fs>
void call_all (int i, float f, const Fs&... fs)
{
// (dispatch(fs, i, f), ...); // C++17
const int dummy[] = {0, (dispatch(fs, i, f), 0)...};
static_cast<void>(dummy);
}
With appropriate function traits has_int_argument. something like:
template <typename ClassOrSig> struct funct_trait;
template <typename C>
struct funct_trait : funct_trait<decltype(&C::operator())> {};
template <typename C, typename Ret, typename ...Args>
struct funct_trait<Ret (C::*) (Args...)> : funct_trait<Ret(Args...)> {};
template <typename C, typename Ret, typename ...Args>
struct funct_trait<Ret (C::*) (Args...) const> : funct_trait<Ret(Args...)> {};
// &&, &, volatile, ... (C ellipsis)
template <typename Ret, typename ...Args>
struct funct_trait<Ret (*)(Args...)> : funct_trait<Ret(Args...)> {};
template <typename Ret, typename ...Args>
struct funct_trait<Ret (Args...)>
{
using sig_type = Ret(Args...);
using args_tuple = std::tuple<Args...>;
// ...
};
template <typename T>
using has_int_argument = std::is_same<std::tuple<int>,
typename funct_trait<T>::args_tuple>;
Demo
template<class...Fs>struct overloaded:Fs...{
using Fs::operator()...;
};
template<class...Fs>
overloaded(Fs...)->overloaded<Fs...>;
the above is a bit trickier in c++14, but implementations exist all over the place.
namespace details {
struct secret_tag {};
struct secret_result {
template<class...Ts>
secret_tag operator()(Ts&&...) const;
};
template<class F>
using secret_tester = overloaded<std::decay_t<F>, secret_result>;
}
template<class F, class Arg>
using match_arg_exactly = std::integral_constant<
bool,
!std::is_same<
details::secret_tag,
std::result_of_t< details::secret_tester<F>(Arg) >
>{}
>;
now we can ask for a given object if it can match a specific argument exactly.
template <typename HasIntArgument>
void call_one(int i, float f, std::true_type, const HasIntArgument & hia)
{
hia (i);
}
template <typename HasFloatArgument>
void call_one(int i, float f, std::false_type, const HasFloatArgument& hia)
{
hia (f);
}
template <typename F>
void call_one(int i, float f, const F & hia)
{
call_one( i, f, match_arg_exactly<const F&, int>{}, hia );
}
and we use this:
void call_all (int, float)
{}
template<class F, class...Fs>
void call_all (int i, float f, F const& f0, Fs const&...fs) {
call_one( i, f, f0 );
call_all(i, f, fs...);
}
Test code:
struct float_eater {
void operator()(float x)const{ std::cout<< "float "<<x<<"\n"; }
};
struct int_eater {
void operator()(int x)const{ std::cout<< "int "<<x<<"\n"; }
};
call_all( 42, 3.14, float_eater{}, int_eater{}, int_eater{} );
Live example
A c++14 overloaded is something like:
template<class...Fs>
struct overloaded;
template<class F0>
struct overloaded<F0>:F0 {
overloaded(F0 f0):F0(std::move(f0)) {}
using F0::operator();
};
template<class F0, class F1>
struct overloaded<F0, F1>: F0, F1 {
overloaded( F0 f0, F1 f1 ):F0(std::move(f0)), F1(std::move(f1)) {}
using F0::operator();
using F1::operator();
};
template<class F0, class...Fs>
struct overloaded<F0, Fs...>:
overloaded<F0, overloaded<Fs...>>
{
overloaded(F0 f0, Fs...fs):
F0(std::move(f0)),
overloaded<Fs...>( std::move(fs)... )
{}
};
which I think is sufficient for our purposes. (More generally, you either make a binary tree, balanced or not), and handle perfect forwarding, and... etc.
Is it possible to create a standalone template function which has a template parameter auto MEMFN (a member function pointer), and has the same return and parameter types as MEMFN has?
So, if MEMFN's type is
RETURN (OBJECT::*)(PARAMETERS...)
then the desired function is this:
template <auto MEMFN>
RETURN foo(OBJECT &, PARAMETERS...);
My problem is how to extract PARAMETERS... from MEMFN's type (RETURN and OBJECT are easy to do).
So I can call this function like this:
Object o;
foo<&Object::func>(o, <parameters>...);
As for request from n.m., here is a stripped down example from an actual code:
#include <utility>
template <typename RETURN, typename OBJECT, typename ...PARAMETERS>
struct Wrapper {
template <RETURN (OBJECT::*MEMFN)(PARAMETERS...)>
RETURN foo(PARAMETERS... parameters) {
// do whatever with MEMFN, parameters, etc. here, not part of the problem
}
};
struct Object {
template <auto MEMFN, typename RETURN, typename OBJECT, typename ...PARAMETERS>
RETURN call(OBJECT &&object, PARAMETERS &&...parameters) {
// here, MEMFN parameters and PARAMETERS must be the same
// Wrapper actually not created here, it is accessed by other means
Wrapper<RETURN, typename std::decay<OBJECT>::type, PARAMETERS...> w;
return w.template foo<MEMFN>(std::forward<PARAMETERS>(parameters)...);
}
};
struct Foo {
void fn(int);
};
int main() {
Object o;
Foo f;
o.call<&Foo::fn, void, Foo &, int>(f, 42);
// this is wanted instead:
// o.call<&Foo::fn>(f, 42);
}
Yes we can:
template <auto MemFn>
struct fooHelper;
template <typename Ret, typename Obj, typename ... Args, Ret (Obj::*MemFn)(Args...)>
struct fooHelper<MemFn>
{
static Ret call(Obj& obj, Args... args) {
return (obj.*MemFn)(args...);
}
};
template <auto MemFn, typename ... Args>
auto foo(Args ... args)
{
return fooHelper<MemFn>::call(args...);
}
Another way to define foo which doesn't introduce a brand new parameter pack is:
template <auto MemFn>
auto& foo = fooHelper<MemFn>::call;
Example usage:
#include <iostream>
struct moo
{
int doit (int x, int y) { return x + y; }
};
int main()
{
moo m;
std::cout << foo<&moo::doit>(m, 1, 2) << "\n";
}
(Perfect forwarding omitted for simplicity)
If you relax your demand on being standalone you can do something like:
#include <iostream>
template <auto MEMFN, class = decltype(MEMFN)>
struct S;
template <auto MEMFN, class Ret, class T, class... Args>
struct S<MEMFN, Ret (T::*)(Args...)> {
static Ret foo(T &o, Args... args) {
(o.*MEMFN)(args...);
}
};
struct A {
void foo(int a, int b) {
std::cout << a << " " << b << std::endl;
}
};
int main() {
A a;
S<&A::foo>::foo(a, 1, 2);
}
[live demo]
If no then you gonna have to have a patience to create a function overloads for each possible number of parameters:
#include <type_traits>
#include <tuple>
#include <iostream>
template <class, std::size_t>
struct DeduceParam;
template <class Ret, class T, class... Args, std::size_t N>
struct DeduceParam<Ret (T::*)(Args...), N> {
using type = std::tuple_element_t<N, std::tuple<Args...>>;
};
template <class>
struct DeduceResultAndType;
template <class Ret, class T, class... Args>
struct DeduceResultAndType<Ret (T::*)(Args...)> {
using result = Ret;
using type = T;
static constexpr decltype(sizeof(T)) size = sizeof...(Args);
};
template <auto MEMFN, class DRAT = DeduceResultAndType<decltype(MEMFN)>, std::enable_if_t<DRAT::size == 1>* = nullptr>
typename DRAT::result foo(typename DRAT::type o, typename DeduceParam<decltype(MEMFN), 0>::type param1) {
}
template <auto MEMFN, class DRAT = DeduceResultAndType<decltype(MEMFN)>, std::enable_if_t<DRAT::size == 2>* = nullptr>
typename DRAT::result foo(typename DRAT::type o, typename DeduceParam<decltype(MEMFN), 0>::type param1,
typename DeduceParam<decltype(MEMFN), 1>::type param2) {
}
struct A {
void foo(int a, int b) {
std::cout << a << " " << b << std::endl;
}
};
int main() {
A a;
foo<&A::foo>(a, 1, 2);
}