I know I can do this:
template<typename T, typename Ret, typename A1, typename A2, Ret(T::*F)(A1, A2)>
class C{}
But as you can see this A1 and A2 are bit ugly. In fact I don't know the number of arguments. Sounds like a work for variadic templates. Unfortunately I can't do this:
// doesn't work - parameter pack must appear at the end of the template parameter list
template<typename T, typename Ret, typename... Args, Ret(T::*F)(Args...)>
class C{}
Nor this:
template
class C;
// doesn't work - wrong syntax
template<typename T, typename F, typename Ret, typename... Args>
class Delegate2<Ret(T::*F)(Args...)>{}
Do I want too much?
You could do the following:
template<typename T, T> struct C;
template<typename T, typename R, typename ...Args, R (T::*F)(Args...)>
struct C<R (T::*)(Args...), F> {
R operator()(T &obj, Args &&... args) {
return (obj.*F)(std::forward<Args>(args)...);
}
};
and then in your program:
struct A {
int foo(int i) { return i; }
};
int main() {
C<int(A::*)(int), &A::foo> c;
A a;
std::cout << c(a, 42) << std::endl;
}
Live Demo
template<class T>struct tag{using type=T;};
template<class Tag>using type=typename Tag::type;
template<class T, class Sig>
struct member_function_pointer;
template<class T, class Sig>
using member_function_pointer_t=type<member_function_pointer<T,Sig>>;
template<class T, class R, class...Args>
struct member_function_pointer<T, R(Args...)>:
tag<R(T::*)(Args...)>
{};
then
template<class T, class Sig, member_function_pointer_t<T,Sig> mf>
class C{};
should do the trick. If you need access to Args..., you can specialize.
template<class T, class Sig, member_function_pointer_t<T,Sig> mf>
class C;
template<class T, class R, class...Args, member_function_pointer_t<T,R(Args...)> mf>
class C<T, R(Args...), mf> {
};
like that.
Related
#include <utility>
#include <iostream>
int main()
{
using std_type = std::remove_reference<void (__attribute__((stdcall)) &)(int) noexcept>::type;
using cdecl_type = std::remove_reference<void (__attribute__((cdecl)) &)(int) noexcept>::type;
using type = std::remove_reference<void (&)(int) noexcept>::type;
std::cout<<typeid(std_type).name()<<"\n";
std::cout<<typeid(cdecl_type).name()<<"\n";
std::cout<<typeid(type).name()<<"\n";
}
Output:
U7stdcallDoFviE
U5cdeclDoFviE
U5cdeclDoFviE
If I compare the types with std::is_same<std_type, cdecl_type>::value it returns false.
I need to remove the attribute so that the following code works, without having to have specializations for __stdcall:
template<typename T>
struct remove_class {};
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...)>
{
using type = R(A...);
};
template <typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const>
{
using type = R(A...);
};
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) volatile>
{
using type = R(A...);
};
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) noexcept>
{
using type = R(A...);
};
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const volatile>
{
using type = R(A...);
};
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const noexcept>
{
using type = R(A...);
};
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) volatile noexcept>
{
using type = R(A...);
};
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const volatile noexcept>
{
using type = R(A...);
};
template<typename T>
struct function_signature
{
using type = typename remove_class<decltype(&std::remove_reference<T>::type::operator())>::type;
};
template<typename R, typename... A>
struct function_signature<R(A...)>
{
using type = R(A...);
};
and:
template<typename T>
struct function_arguments_type
{
using type = typename function_arguments_type<typename function_signature<T>::type>::type;
};
template<typename R, typename... A>
struct function_arguments_type<R(A...)>
{
using type = typename std::tuple<A...>;
};
So that I can determine what is the return type of a function, and what is the type of its arguments.
Is there a way to remove the __attribute__((....)) from a function's signature or at least make my templates work without having to specialize every single one of them for __stdcall?
You can still create a traits remove_stdcall, something like:
template <typename Func>
struct remove_stdcall
{
using type = Func;
};
template <typename Ret, typename ... Args>
struct remove_stdcall<Ret __attribute__((stdcall)) (Args...) noexcept>
{
using type = Ret(Args...) noexcept;
};
template <typename Ret, typename ... Args>
struct remove_stdcall<Ret __attribute__((stdcall))(Args...)>
{
using type = Ret(Args...);
};
Demo.
Using the following metafunction front to get the first type of a typelist I try to write a similar metafunction to extract the first template of a list of templates.
namescpace detail {
template<typename L> struct front_impl;
template<template<typename, typename...> typename L, typename F, typename... I>
struct front_impl<L<F, I...>> {
typedef F type;
};
}
template<typename L> struct front_impl;
template<template<typename, typename...> typename L, typename F, typename... I>
struct front_impl<L<F, I...>> {
typedef F type;
};
One can use this as follows:
template<typename... T>
struct List {
inline static constexpr size_t size = sizeof...(T);
};
using l1 = List<A, B, C>;
using f1 = front<l1>;
Now I try to do the same with a list of templates. Therefore I use a list of templates TList:
template<template<typename> typename... TT>
struct TList {
inline static constexpr size_t size = sizeof...(TT);
};
and the metafunction tfront:
template<typename T> struct tfront;
template<template<typename> typename F, template<typename> typename... R>
struct tfront<TList<F, R...>> {
template<typename T> using type = F<T>;
};
Then I can extract the first of a list of templates A, B, ... (not shown here):
using tlist = TList<A, B, C>;
template<typename T>
using f = typename tfront<tlist>::template type<T>;
f<int> xx;
Then xx ist of type A<int>.
The Question is: can I write the metafunction tfront in the same way as front, that is not as a partial specialization for the list of templates TList but for every variadic template of templates? So I would like to introduce a parameter L for tfront as a template-template-parameter with a variadic list of templates, so that the compiler must also deduce the type of the type L as in the case of front.
I would like to write something like (but what to use as ???):
template<template<typename> typename F, ??? TL, template<typename> typename... R>
struct tfront<TL<F, R...>> {
template<typename T> using type = F<T>;
};
You need an extra layer of template<typename> typename...:
template<typename>
struct tfront;
template<template<typename> typename F,
template<template<typename> typename...> typename TL,
template<typename> typename... R>
struct tfront<TL<F, R...>>
{
};
live example on wandbox
I'm trying to implement an std::tuple through variadic template with recursive inheritance and external get function. I works well as long as tuple has public inheritance and public value field. But i need to make them private and to accomplish it i need to write a friend "get" function in the tuple. But the problem is that returned type of "get" is calculated through other variadic template. So I don't know what to write as returned value of that friend function.
#include <iostream>
#include <type_traits>
template <typename... Ts>
class Tuple{};
template <typename T, typename... Ts>
class Tuple<T, Ts...> : public Tuple<Ts...>
{
// template<size_t k, typename T1, typename... T1s>
// friend typename tuple_element<k, tuple<T1, T1s...>>::type&
// get(Tuple<T1, T1s...>& t);
public:
T m_head;
};
template<size_t index, typename>
struct tuple_element;
template<typename T, typename... Ts>
struct tuple_element<0, Tuple<T, Ts...>>
{
typedef T type;
};
template<size_t k, typename T, typename... Ts>
struct tuple_element<k, Tuple<T, Ts...>>
{
typedef typename tuple_element<k-1, Tuple<Ts...>>::type type;
};
template<size_t k, typename... Ts>
typename std::enable_if<k==0,
typename tuple_element<0, Tuple<Ts...>>::type&>::type
get(Tuple<Ts...>& t)
{
return t.m_head;
}
template<size_t k, typename T, typename... Ts>
typename std::enable_if<k!=0,
typename tuple_element<k, Tuple<T, Ts...>>::type&>::type
get(Tuple<T, Ts...>& t)
{
Tuple<Ts...>& super = t;
return get<k-1>(super);
}
int main(int argc, char* argv[])
{
Tuple<int, int, std::string> t;
get<2>(t) = "3.14";
std::cout << get<2>(t) << std::endl;
}
Commented code was my attempt to write such function but it doesn't work.
Forward-declare tuple_element and then make friends from the two overloaded get functions:
template <size_t index, typename>
struct tuple_element;
template <typename T, typename... Ts>
class Tuple<T, Ts...> : Tuple<Ts...>
{
template <size_t k, typename... Us>
friend typename std::enable_if<k==0, typename tuple_element<0, Tuple<Us...>>::type&>::type get(Tuple<Us...>& t);
template <size_t k, typename U, typename... Us>
friend typename std::enable_if<k!=0, typename tuple_element<k, Tuple<U, Us...>>::type&>::type get(Tuple<U, Us...>& t);
private:
T m_head;
};
DEMO
template<typename... Args>
class SomeClass
{
using tuple_type = std::tuple<Args...>; // (ie: <bool,int,bool>)
tuple_type mytuple;
};
template<typename T, typename C, typename... I> // T is SomeClass
class SomeOtherClass
{
void fn(void(C::*f)(bool,int,bool)); // I want this
// based on the T::tuple_type but I'm not sure how.
};
I could simply use tuple_element 3 times if i knew the tuple has 3 elements only, but I don't know that.
Write a generic type trait:
template <class C, class F>
struct mem_ptr;
template <class C, class F>
using mem_ptr_t = typename mem_ptr<C, F>::type;
And specialize it for tuple:
template <class C, class... Args>
struct mem_ptr<C, std::tuple<Args...>> {
using type = void (C::*)(Args...);
};
And then use it:
void fun(mem_ptr_t<C, typename T::tuple_type> f);
This assumes you want void as the return type.
Could generalize this to splitting up the mem_ptr part from the tuple to func part:
template <class C, class F>
struct mem_ptr {
using type = F C::*;
};
template <class C, class F>
using mem_ptr_t = typename mem_ptr<C, F>::type;
template <class R, class T>
struct tuple_to_func;
template <class R, class... Args>
struct tuple_to_func<R, std::tuple<Args...>> {
using type = R(Args...);
};
template <class R, class T>
using tuple_to_func_t = typename tuple_to_func<R, T>::type;
In which case you'd want:
void fun(mem_ptr_t<C,
tuple_to_func_t<void, typename T::tuple_type>
> f);
I try to learn a little bit about template metaprogramming and
currently i play around with variadic templates.
In his talk "Variadic Templates are Funadic" Alexandrescu introduces a
small tuple implementation, which i try to build and maybe extend a
little bit. (I know it is a toy example, i just try to learn a little
bit more about c++). However, i have a small problem with his code.
Here it is:
template <typename... Ts>
class tuple
{};
template<size_t, typename> struct tuple_element;
template<typename T, typename... Ts>
struct tuple_element<0, tuple<T, Ts...>>
{
typedef T type;
};
template <size_t k, typename T, typename... Ts>
struct tuple_element<k, tuple<T, Ts...>>
{
typedef
typename tuple_element<k-1,tuple<Ts...>>::type type;
};
template<size_t k, typename... Ts>
typename std::enable_if<k == 0,
typename tuple_element<0,tuple<Ts...>>::type&>::type
get(tuple<Ts...>& t)
{return t.head_;}
template<size_t k, typename T, typename... Ts>
typename std::enable_if<k != 0,
typename tuple_element<k,tuple<T,Ts...>>::type&>::type
get(tuple<T,Ts...>& t)
{
tuple<Ts...> & super = t;
return get<k-1>(super);
}
template <typename T, typename... Ts>
class tuple<T,Ts...> : private tuple<Ts...>
{
private:
T head_;
};
int main(int argc, char *argv[])
{
tuple<int,std::string> t;
get<0>(t) = 10;
get<1>(t) = std::string("test");
std::cout<<get<0>(t)<<std::endl;
}
In order to work correctly, the get function must be friend of the
tuple class (It is also mentioned on this slides, see 32). But how
does the friend declaration looks like? I tried different approaches
but could not get it to work. When i change the code from private to public inheritance
and change the access rules for head_ to public it works.
Thanks for your help
Kevin
This works for me:
template <typename T, typename... Ts>
class tuple<T,Ts...> : private tuple<Ts...>
{
private:
T head_;
template<size_t k, typename T1, typename... T1s>
friend typename std::enable_if<k != 0,
typename tuple_element<k,tuple<T1,T1s...>>::type&>::type
get(tuple<T1,T1s...>& t);
template<size_t k, typename... T1s>
friend typename std::enable_if<k == 0,
typename tuple_element<0,tuple<T1s...>>::type&>::type
get(tuple<T1s...>& t);
};
Demo.
Another implementation from the other point of view:
#include <iostream>
#include <type_traits>
template <class... Args>
class Tuple;
template <>
class Tuple<> {};
template <class T, class... Args>
class Tuple<T, Args...>: public Tuple<Args...> {
using Base = Tuple<Args...>;
T Value_;
public:
Tuple(T&& value, Args&&... args)
: Value_(std::forward<T>(value))
, Base(std::forward<Args>(args)...)
{
}
T& Value() {
return Value_;
}
};
template <size_t k, class T, class... Args>
struct Select {
using Type = typename Select<k - 1, Args...>::Type;
};
template <class T, class... Args>
struct Select<0, T, Args...> {
using Type = T;
};
template <size_t k, class... Args>
using TSelect = typename Select<k, Args...>::Type;
template <bool P, class T>
using TEnableIf = typename std::enable_if<P, T>::type;
template <size_t k, class T, class... Args>
TEnableIf<(k != 0), TSelect<k, T, Args...>&> get(Tuple<T, Args...>& t) {
return get<k - 1, Args...>(t);
}
template <size_t k, class T, class... Args>
TEnableIf<(k == 0), TSelect<k, T, Args...>&> get(Tuple<T, Args...>& t) {
return t.Value();
}
int main() {
Tuple<int, char> t(1, 'a');
std::cout << get<0>(t) << std::endl;
std::cout << get<1>(t) << std::endl;
get<1>(t) = 'b';
std::cout << get<1>(t) << std::endl;
}
Actually, we don't need a Tuple to get a type.