Generalized Mixins - c++

I was writing some code where I have a class that can accept mixins as variadic template parameters. However, I also need the mixins to be able to access the base class through the CRTP idiom. Here's a minimal example that cannot quite do what I want:
template <template <class> class... Mixins>
class Foo : Mixins<Foo<Mixins...>>... {};
However, a mixin that I might pass to Foo will, in general, have several template parameters, like so:
template <class Derived, class Type1, class Type2>
class Bar
{
Derived& operator()()
{
return static_cast<Derived&>(*this);
}
};
How can I change Foo so that I can have it inherit from a number of base classes, where I control the template parameters accepted by each base class? If I hand Foo a list of template-template parameters, along with a list of arguments to pass to them, then I don't see how I would be able to associate each template-template parameter with its arguments. So far, I thought of something like this, but I don't know how I would proceed.
template <template <class...> class T,
template <class...> class... Ts>
class Foo : /* How do I retrieve the arguments? */

I am not quite sure I understood the problem, so please let me rephrase it so that we can start on the right foot.
You need to thread the derived type to the base classes, in a typical CRTP use case, while at the same time passing other template parameter to the various base classes.
That is, a typical base class will be:
template <typename Derived, typename X, typename Y>
struct SomeBase {
};
And you want need to create your type so that you can control the X and Y and at the same time pass the complete Derived class.
I think I would use the apply trick to generate the base class on the fly, from an adapter provided in the argument list of the Derived class.
template <typename Derived, typename X, typename Y>
struct SomeBase {};
template <typename X, typename Y>
struct SomeBaseFactory {
template <typename Derived>
struct apply { typedef SomeBase<Derived, X, Y> type; };
};
// Generic application
template <typename Fac, typename Derived>
struct apply {
typedef typename Fac::template apply<Derived>::type type;
};
Then, you would create the type as:
typedef MyFoo< SomeBaseFactory<int, float> > SuperFoo;
Where Foo is defined as:
template <typename... Args>
struct Foo: apply<Args, Foo<Args...>>::type... {
};
And just because it's been a while since I trudged so deeply in templates, I checked it worked.
Of course, the Factory itself is not really a specific to a given type, so we can reuse the wrapper approach you had experimented:
template <template <typename...> class M, typename... Args>
struct Factory {
template <typename Derived>
struct apply { typedef M<Derived, Args...> type; };
};
And yes, it works too.

If I understand your question correctly, you should create template aliases that reduce each mixin to a single template parameter.
template <typename Derived>
using BarIntFloat = Bar<Derived, Int, Float>;
template <typename Derived>
using BazQux = Baz<Derived, Qux>;
typedef Foo<BarIntFloat, BazQux> MyFoo;

Here's a solution I came up with. There may be a more elegant way to do this, but I couldn't think of any. One caveat is that all of the mixins used need to first be nested in the wrapper struct, along with their respective arguments.
template <template <class...> class Mixin, class... Args>
struct wrapper
{
typedef Mixin<Args...> type;
};
template <class... Args>
struct test
{
};
template <class Arg, class... Args>
struct test<Arg, Args...> : Arg::type, test<Args...>
{
};
template <class T>
class mixin1 {};
template <class T1, class T2>
class mixin2 {};
template <class T1, class T2, class T3>
class mixin3 {};
int main()
{
test<wrapper<mixin1, int>, wrapper<mixin2, int, float>> foo;
return 0;
}

#void-pointer
This is basic omission of variadic templates. User cannot get i-th type from T... or get i-th value from values...
Here is a link from going native 2012 lecture by Andrei Alexandrescu:
template <typename... Ts>
void fun(const Ts&... vs) {}
• Ts is not a type; vs is not a value!
typedef Ts MyList; // error!
Ts var; // error!
auto copy = vs; // error!
So Ts/vs should be some kind of tuple.

Related

Is it possible to create a template template parameter list?

I was wondering whether it's possible to make a list containing template template parameters, like
template <
template <typename...> class TTP0,
template <typename...> class... TTPs
>
struct TTP_List : TTP_List<TTPs...> {};
A problem I encountered is that I did not know a good way to access the elements of the list, that is, TTP0. I would like to use type aliases, typedef or using. I however know this is not possible, because the template template parameters are not types and must therefor not be treated as such.
A approach I could imagine working is making explicit structs to read the data and make it use specializations, such as:
template <template <typename...> class>
struct container_TTPs;
template <template <typename...> class TTP>
struct container_TTPs<std::vector> {};
However, this approach seems very explicit. Is there a way to accomplish this recognition without this use of template specialization?
Feel free to ask if I need to elaborate.
EDIT: For example, I want to be able to use certain expressions for every held type, such as TestClass<TTP_List<std::vector, std::list>>::value, where TestClass uses the std::vector and the std::list, without requiring a variadic template within TestClass, so that multiple TTP_Lists can be passed.
I don't understand what do you mean with "access the elements of the list".
It seems to me that you should give us an example of what do you want, concretely, do accessing elements of the list.
Anyway, as you can use using to "access" (?) typenames
template <typename T0, typename ... Ts>
struct foo
{
using type = T0;
};
you can use a template using to "access" (?) a template-template parameter as follows
template <template <typename...> class T0,
template <typename...> class ... Ts>
struct foo
{
template <typename ... As>
using templ_type = T0<As...>;
};
and you can use it in this way
// vi is a std::vector<int>
foo<std::vector, std::set, std::map>::templ_type<int> vi { 0, 1, 2 };
The problem (a problem) is that a template parameter variadic list (isn't important if of typenames, of values or of template-templates) must be in last position.
So
template <typename ... Ts, typename T0>
struct foo
{ };
is wrong, because Ts... must be in last position, and
template <typename T0, typename ... Ts>
struct foo
{ };
is correct.
With template-template parameters,
template <template <typename ...> class ... Ts,
template <typename ...> class T0>
struct foo
{ };
is wrong where
template <template <typename ...> class T0,
template <typename ...> class ... Ts>
struct foo
{ };
is correct.

Why can't we use variadic template at the beginning/middle of template specialization (and how to emulate)?

I was wondering how to emulate the following:
template<class> struct foo;
template<template<class..., int..., class...> class list,
class... clist1, int... ilist1, class... clist2>
struct foo<list<clist1..., ilist1..., clist2...>> {
};
This specialization (hypothetically) accepts a class with any number of classes, then integers, then classes. Currently there seems to be no way to directly implement this. (Bonus points if you can comment on why the standard doesn't support this)
An example of when this would be practical is in Eigen's linear algebra library where most classes are structures like:
Vector<class Scalar_type, int rows, class... options>
Mstrix<class Scalar_type, int rows, int cols, class... options>
With the above enabled, meta-template functions could be used that accept any of these base classes. Because it is not supported you have to write specializations for each class.
Is there any way to emulate a template function that supports accepting classes like the above?
I am looking for a generic solution. (Writing specializations for each class is not generic, and I am not directly looking for a solution to Eigen's library, that is just an example)
Example for clarification
Lets say I want to get the first class of a template class.
Somehow I get the original class type from some other meta-template function. Ergo I don't know what it's template parameters look like.
Maybe it's:
Vector1<class Scalar_type, int rows, class... others>
Or
Vector2<class Scalar_type, class... others>
Because I'm not directly using the type my meta template function must be of something like template<class> struct foo; with various specializations.
In this case getFront is a good example as I would need 2 specializations:
template<class> struct getFront;
template<template<class...,int...,class...> class param,
class... l1, int... l2, class... l3, class first>
struct getFront<param<first, l1..., l2... l3....> {
using type = first; };
and
template<template<class...> class param, class first, class... others>
struct getFront<param<first, others...>> {
using type = first;
};
Is there any way to emulate a template function that supports accepting classes like the above?
What about using template specialization as follows ?
template <typename...>
struct foo;
template <typename ... Ts1, int ... Is, typename ... Ts2>
struct foo<std::tuple<Ts1...>,
std::integer_sequence<int, Is...>,
std::tuple<Ts2...>>
{
};
Or, if you prefer parametrize the template containers, something like
template <template <typename...> class Ct1, typename ... Ts1,
template <int...> class Ci, int ... Is,
template <typename...> class Ct2, typename ... Ts2>
struct foo<Ct1<Ts1...>, Ci<Is...>, Ct2<Ts2...>>
{ };

Template template variadic parameter specialization

I was wondering if there was a way to specialize a template in the following way:
template<typename... Ts>
class Typelist { };
template<template<typename> typename... TTs>
class Typelist<TTs<typename>> { }; //I don't know if that is the right syntax, at least the compiler doesn't complain
I want it to work as a list of templated types as well as a list of non-templated types:
template<typename T>
class AT {};
template<typename T>
class BT {};
template<typename T>
class CT {};
int main() {
using tl1 = Typelist<int, float, double>; //works fine
using tl2 = Typelist<AT, BT, CT>; //gives an error
}
Edit:
If I declare the secont Typelist as a seperate type it works...
template<template<typename> typename... TTs>
class Typelist2 { };
//...
using tl2 = Typelist2<AT, BT, CT>; //compiler doesn't complain and it works fine
I was wondering though if it was possible to use only Typelist for both cases so that Typelist2 doesn't have to be a seperate type.
Can anybody help me?
I was wondering though if it was possible to use only Typelist for both cases so that Typelist2 doesn't have to be a seperate type.
I don't think so.
Because TypeList is defined as template<typename... Ts> or template<template<typename> typename... TTs>; both definition can't work togheter.
The best I can imagine to help you is define a TypeList base version for simple types
template <typename ... Ts>
struct TypeList
{
// here you can use Ts...
};
and a specialization for containers (with only a type in it) as follows
template <template <typename> class ... Tts, typename ... Ts>
struct TypeList<Tts<Ts>...>
{
// here you can use Ts... and Tts...
};
where you can use Ts and Tts.
But isn't a great solution because you can't define a containers TypeList simply as
TypeList<AT, BT, CT> tcl;
but you have to add contained dummy (?) types as follows
TypeList<AT<int>, BT<float>, CT<double>> tl2;
Another problem is you can't mix they, so
TypeList<AT<int>, BT<float>, double> tl;
call the base version (no containers) of TypeList.

Throw multiple-template class in a template template parameter - template binding?

Given the following class:
template <class T, template <typename> class B>
class A { B<T> b; };
I can now write code like such:
A<float, MyVector> a1;
A<int, MySet> a2;
What is the most elegant way to put multi-parameter classes of which all parameters are specified except one, in B? Like a map with int-keys? The only thing I can come up with is this:
template <class U> using C = MyMap<int, U>;
A<float, C<int>> a3;
Is there such a template equivalent to std::bind, where we can provide only a part of the parameters and leave one of them open? I'm quite sure the language doesn't provide for this, but people must've solved this before.
A<float, MyMap<int, _>> a3;
There isn't a built-in template equivalent to std::bind, but you can write one yourself. Here's a simple version which binds the first template argument which you could extend to suit your needs:
template <typename T, template <typename...> class B>
struct bind_t1 {
template <typename... Ts>
using type = B<T,Ts...>;
};
Then you just use bind_t1 like so:
A<float, bind_t1<int, std::map>::type> a3;
Note that for your example, you'll need to modify your template parameters to take a variadic template template:
template <class T, template <typename...> class B>
class A { B<T> b; };
Here's a slightly extended version which can bind a number of contiguous elements at the start of the parameter list:
template <template <typename...> class B, typename... Ts>
struct bind_nt1 {
template <typename... Us>
using type = B<Ts...,Us...>;
};
//Usage
A<std::less<int>, bind_nt1<std::map, int, float>::type> a3;
Here's a generic version based on the way std::bind does things. It doesn't do any validation and probably has some edge cases, but it's a good starting point. Thanks to Piotr Skotnicki for improvements.
template <std::size_t N>
struct placeholder{};
template <template <typename...> class B, typename... Ts>
struct bind_t {
private:
template <typename T, typename UTuple>
struct resolve_placeholder {
using type = T;
};
template <std::size_t N, typename UTuple>
struct resolve_placeholder<placeholder<N>, UTuple> {
using type = typename std::tuple_element<N-1, UTuple>::type;
};
public:
template <typename... Us>
using type = B<typename resolve_placeholder<Ts, std::tuple<Us...>>::type...>;
};
//Usage
A<int, bind_t<std::map, float, placeholder<1>, std::less<float>>::type> a3;
Using this, you can even change the order of template parameters:
//std::map<int,float>
bind_t<std::map, placeholder<2>, placeholder<1>>::type<float, int> b;

Applying partially applied template

Having a class like the A, is there a way to apply it to a template like this of B, with T2 set to some type C? But without creating another template class inheriting from A.
template<typename T1, typename T2>
class A
{ };
template<template <typename T1> class T3>
class B
{ };
With C++11 using a template alias works:
template<typename T1, typename T2>
class A
{ };
template<template <typename T1> class T3>
class B
{ };
class C
{ };
template< typename T > using A1 = A< T, C >;
int main()
{
B< A1 > b;
}
without C++11, you are left with what you probably already know:
template< typename T > class A1 : A< T, C > {};
I will propose an alternative solution: do not use template template parameters.
If you write:
template <typename T> struct B {};
Then it can be used with A<int, int> or C<3> or even plain D.
Whilst it is possible to use template template parameters, it is general a bad idea. You should treat the template parameter of a class as an implementation detail and apply the golden rule: do not rely on implementation details.
If you need access to the type, somehow, then use an associated type (aka T::AssociatedType) or a trait (BTraits<T>::AssociatedType).
EDIT: dealing with multiple instantiations of the template template parameter.
Suppose we want to "erase" the template template parameter of such a class:
template <template <typename> class A>
struct Something {
template <typename T>
void doit() { A<T>::doit(); }
};
The C++ standard allocation model is to use an inner rebind structure:
template <typename T>
struct Simple {
template <typename U>
struct rebind { typedef Simple<U> type; };
};
template <typename T0, typename T1>
struct Multi {
template <typename U>
struct rebind { typedef Multi<U, T1> type; };
};
template <typename A>
struct Something {
template <typename T>
void doit() { typedef typename A::rebind<T>::type B; B::doit(); }
};
Note how you can use complex computations in rebind and nothing forces you in blindly passing the type received as parameter.
Whilst another (similar) solution is to ask for a factory (aka, the object passed itself cannot be used but it can build useful objects); for ease of use the C++ containers ask of their allocators that they be both usable in themselves and factories for other types.
Yes, you can do it using C++11's alias template:
template <typename T>
using AA = A<T, C>;
B<AA> b;
Live example