How to create template class with member function pointer? - c++

Is anyone knows how to declare generalized template form for the next template specialization:
template <template <class> class Container,
class Value,
class Return,
Return (Container<Value>::*Apply)(const Value &)>
class Example<Container<Value>, Apply>
{
};
Apply must be a pointer to a member function whoes signature is unknown in template declaration.

Do you mean something like this?
template<typename T, typename F>
struct S;
template<template <typename...> class C, typename R, typename... A>
struct S<C<A...>, R(A...)> {
using Apply = R(C<A...>::*)(A...);
// ...
};
As an example:
template<typename... U>
struct T {
int f(int, char) { return 42; }
};
template<typename T, typename F>
struct S;
template<template <typename...> class C, typename R, typename... A>
struct S<C<A...>, R(A...)> {
using Apply = R(C<A...>::*)(A...);
// ...
};
int main() {
S<T<int, char>, int(int, char)>::Apply apply = &T<int, char>::f;
}
Pretty ugly, indeed, but that's what the OP (maybe) asked.

Related

std::tuple of std::shared_ptr of template parameter pack

I want to implement a class template that:
behaves like a function
it's input and output variables are all shared.
relatively easy to use.
As a result, I construct the following:
// all input/output variable's base class
class basic_logic_parameter;
// input/output variable, has theire value and iterators to functions that reference to this variable
template <typename FuncIterator, typename ValueType>
class logic_parameter
:public basic_logic_parameter
{
private:
std::list<FuncIterator> _refedFuncs;
ValueType _val;
public:
};
// all `function`'s base class
class basic_logic_function
{
public:
virtual ~basic_logic_function() = 0;
};
// the function, has input/output variable
template <typename FuncIterator, typename R, typename... Args>
class logic_function_base
:public basic_logic_function
{
private:
std::shared_ptr<logic_parameter<FuncIterator, R>> _ret;
std::tuple<std::shared_ptr<logic_parameter<FuncIterator, Args>>...> _args;
public:
template <std::size_t N>
decltype(auto) arg()
{
return std::get<N>(_args);
}
template <std::size_t N>
struct arg_type
{
typedef std::tuple_element_t<N> type;
};
template <std::size_t N>
using arg_type_t = arg_type<N>::type;
decltype(auto) ret()
{
return _ret;
}
};
I wish to use as these like:
// drawing need color and a pen
struct Color
{
};
struct Pen
{
};
struct Iter
{
};
class Drawer
:public logic_function_base<Iter, void(Color, Pen)>
{
public:
void draw()
{
arg_type_t<0> pColor; // wrong
}
}
My compiler can not pass this code through, why? I just want convert a template parameter pack to std::tuple of std::shared_ptr of them.
for example:
Given struct A, int, struct C, I want to have:
std::tuple<
std::shared_ptr<logic_parameter<A>>,
std::shared_ptr<logic_parameter<int>>,
std::shared_ptr<logic_parameter<C>>,
>
The problem (once the small errors are fixed1) is that you instantiate:
logic_function_base<Iter, void(Color, Pen)>
...meaning that FuncIterator is Iter and R is void(Color, Pen), so Args is emtpy <>, so decltype(_args) is an empty std::tuple<>, and your code fails to obtain the type of the 0th element of an empty tuple, which is legit.
What you want is partial specialization of logic_function_base:
template <typename F, typename T>
class logic_function_base;
template <typename FuncIterator, typename R, typename... Args>
class logic_function_base<FuncIterator, R(Args...)>: public basic_logic_function {
};
1 Small mistakes in your current code:
template <std::size_t N>
struct arg_type
{
typedef std::tuple_element_t<N, decltype(_args)> type; // Missing the tuple type
};
template <std::size_t N>
using arg_type_t = typename arg_type<N>::type; // Missing a typename
This may not answer your whole question, but you could use the following trait to wrap tuple element types.
template <typename T> struct wrap;
template <typename... T>
struct wrap<std::tuple<T...>> {
using type = std::tuple<std::shared_ptr<logic_parameter<T>>...>;
}
template <typename T>
using wrap_t = typename wrap<T>::type;
You can then use it like this:
std::tuple<int,double,char> t1;
wrap_t<decltype(t)> t2;
The type of t2 is std::tuple<std::shared_ptr<logic_parameter<int>>,std::shared_ptr<logic_parameter<double>>,std::shared_ptr<logic_parameter<char>>>.

Convert tuple to function parameters

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);

Template template and partial specialization: a puzzle

Consider the following code:
template<typename>
struct S { };
template<typename, typename>
struct B;
template <typename R, typename... Args, template<class> class C>
struct B<R(Args...), C<R>> {
void f() { }
};
int main() {
B<void(), S<void>> b;
b.f();
}
It compiles and has no problem.
Anyway, whenever one decides to use B, it has to provide two types.
What I'd like to achieve is to default somehow the second parameter (I know, partial specializations do not accept a default for their parameters) and let an user define it's type as B<void()> instead of B<void(), S<void>>.
Unfortunately, because of template template, partial specialization and the dependency existent between the parameters, all together they lead to a puzzle against which I'm struggling since a couple of hours.
Is there any clever solution to do that?
So far, I have been able to solve it with intermediate structures, but I don't like it so much...
Partial specializations don't accept default parameters, but the primary does. You can just add it there:
template<typename Sig, typename X = S<return_type_t<Sig>>>
struct B;
Then all you need to do is implement a return type metafunction for a signature. Something like:
template <class Sig>
struct return_type;
template <class Sig>
using return_type_t = typename return_type<Sig>::type;
template <class R, class... Args>
struct return_type<R(Args...)> {
using type = R;
};
You may create an helper class for that:
template <typename T> struct default_arg;
template <typename R, typename... Args>
struct default_arg<R(Args...)>
{
using type = S<R>;
};
template<typename Sign, typename T = typename default_arg<Sign>::type>
struct B;
Demo
Here we change B into a template alias.
B_t does the default arg work.
B_impl is the implementation of B without any default args.
B is a using alias that gets the result of B_t.
template<class> struct S {};
template<class, class>
struct B_impl;
template<class R, class... Args, template<class...> class C>
struct B_impl<R(Args...), C<R>> {
void f() { }
};
template<class, class=void>
struct B_t;
template<class R, class...Args>
struct B_t<R(Args...), void>:
B_t<R(Args...),S<R>>
{};
template<class R, class... Args, template<class...> class C>
struct B_t<R(Args...), C<R>> {
using type=B_impl<R(Args...), C<R>>;
};
template<class Sig, class Z=void>
using B=typename B_t<Sig,Z>::type;
The downside is that pattern-matching on B won't work well.

Template class specialization with a template template argument

#include <tuple>
#include <iomanip>
template <typename T, typename ...L>
struct foo{};
template <typename T>
struct bar{
using toto = T;
};
template <template<typename T, typename ...L> class F>
struct bar<F>{
using toto = T
};
int main(){
bar<foo<int,char,char>> a;
}
I want to specialize bar when the argument is a class that has at least one template argument <typename T, typename ...L>
I tried :
template <template<typename T, typename ...L> class F>
struct bar<F<T,L...>>{
using toto = T
};
and
template <template<typename , typename ...> class F, typename T, typename ...L>
struct bar<F<T,L...>>{
using toto = T
};
which may have made sense, but I couldn't get it right
You forgot a lot of stuff on your sample, syntactically speaking
template <typename T, typename... L>
struct foo{};
template <typename T>
struct bar {
using toto = T; // Semicolon missing
};
template <template<typename, typename...> class F, typename T, typename... L>
struct bar<F<T,L...>> { // Wrong pack expansion
using toto = T;
};
int main() { // () missing
bar< foo<int,char,char> > a; // Pass the parameters to foo since you're
// partially specializing bar to just do that
}
Example on ideone
Your ideone code just has a bunch of typographical errors:
struct bar<F<T,...L>>{
//should be
struct bar<F<T,L...>>{
//missing brackets
int main{
//missing semicolon
using toto = T
bar<foo, int,char,char> a;
//should be
bar<foo<int,char,char>> a;
There's a few syntatic issues here.
bar is a template that takes one type argument. So any partial or explicit specialization of bar must also take one type argument.
template <template<typename T, typename ...L> class F>
struct bar<F> {
Here, the T and L names are irrelevent, and really you're specializating on a template template. That doesn't match. You'd have to specialize on a specific instantiation of F:
template <template<typename , typename ...> class F,
typename T, typename... L>
struct bar<F<T, L...>> {
You're missing a semicolon:
using toto = T;
^^
Your declaration of main is missing parentheses:
int main() {
bar<foo<int,char,char>> a;
}

Arbitrary type transformations of functor arguments and results

I have a class something like this:
template <typename T>
struct operation {
typedef T result_type;
typedef ::std::shared_ptr<operation<T> > ptr_t;
};
I have a functor that would match this ::std::function type:
::std::function<int(double, ::std::string)>
I want to create a functor that has a signature something like this:
operation<int>::ptr_t a_func(operation<double>::ptr_t, operation< ::std::string>::ptr_t);
I want to do this in an automated fashion so I can create a similar functor for any given ::std::function type.
Lastly, I would like to put this wrinkle in. This:
::std::function<int(operation<double>::ptr_t, ::std::string)>
should result in this:
operation<int>::ptr_t a_func(operation<double>::ptr_t, operation< ::std::string>::ptr_t);
Because if a functor already accepts an operation<T>::ptr_t that means it understands what they are and is willing to deal with their asynchronous nature itself.
How would I do this? I have a naive and partially working attempt here:
template <typename argtype>
struct transform_type {
typedef typename operation<argtype>::ptr_t type;
};
template <typename ResultType, typename... ArgTypes>
::std::function<typename transform_type<ResultType>::type(typename transform_type<ArgTypes...>::type)>
make_function(::std::function<ResultType(ArgTypes...)>)
{
   return nullptr;
}
It doesn't detect arguments that are already of type std::shared_ptr<operation<T> > though. And this specialization of transform_type fails to compile:
template <typename argtype>
struct transform_type<typename operation<argtype>::ptr_t>
{
typedef typename stub_op<argtype>::ptr_t type;
};
template<template<typename...> class F, typename Sig>
struct transform;
template<template<typename...> class F, typename R, typename... A>
struct transform<F, R(A...)> {
using type = typename F<R>::ptr_t(typename F<A>::ptr_t...);
};
Usage looks like:
template<typename Sig>
void foo(std::function<Sig> f)
{
using transformed_type = typename transform<operation, Sig>::type;
std::function<transformed_type> g;
}
As for the specialization to avoid transforming types that are already in the desired form:
template<typename T>
struct operation<std::shared_ptr<T>> {
using ptr_t = std::shared_ptr<T>;
using result_type = ptr_t; // Or perhaps this needs to be T, you haven't said
};
I believe I have figured it out with R. Martinho Fernandez's help:
template <typename T>
struct is_op_ptr {
private:
// Returns false_type, which has a ::value that is false.
template <class AT>
static constexpr std::false_type is_it_a_ptr(...);
// Returns true_type (if enable_if allows it to exist).
template <class AT>
static constexpr typename ::std::enable_if<
::std::is_same<
AT,
typename operation<typename AT::element_type::result_type>::ptr_t>::value,
std::true_type>::type // note the true_type return
is_it_a_ptr(int); // no definition needed
public:
// do everything unevaluated
static constexpr bool value = decltype(is_it_a_ptr<T>(0))::value;
};
template <typename T>
struct transform_type
: ::std::conditional< is_op_ptr<T>::value, T, typename operation<T>::ptr_t>
{
};
This also allows me to query whether or not a type will be transformed in the construction of the wrapper function.