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

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;

Related

How to alias a nested template class with variadic parameter packs

Is there any way one can alias a nested template class with a using keyword? Something like this
template <typename... Types>
struct Something {
template <typename... TypesTwo>
struct Another {};
};
template <typename... Types>
template <typename... TypesTwo>
using Something_t = typename Something<Types...>::template Another<TypesTwo...>;
int main() {
Something_t<int><double>{};
return 0;
}
This answer template template alias to a nested template? shows a way to do that but that will no longer work if both the parameter packs are variadic, as the compiler will not know where to start and where to end the type lists.
Not exactly what you asked but... if you can wrap your variadic type lists as arguments of tuples (or similar classes)...
#include <tuple>
template <typename ... Types>
struct Something
{
template <typename ... TypesTwo>
struct Another {};
};
template <typename, typename>
struct variadicWrapper;
template <typename ... Ts1, typename ... Ts2>
struct variadicWrapper<std::tuple<Ts1...>, std::tuple<Ts2...>>
{ using type = typename Something<Ts1...>::template Another<Ts2...>; };
template <typename T1, typename T2>
using Something_t = typename variadicWrapper<T1, T2>::type;
int main()
{
Something_t<std::tuple<int>, std::tuple<double>>{};
}
Not a standalone answer, but an addition to max66's answer:
You could have tried this:
template<typename ... TT, typename ... TTT>
using Alias = typename Something<TT...>::Another<TTT...>;
Looks really nice at first, doesn't it?
Problem then, however will already be with one single template parameter:
Alias<int> a;
Which one is it now? Something<int>::Another<> or Something<>::Another<int>? And if you have more parameters, how to distribute? No chance to get a meaningful solution. So no, you can't do that directly, you have to help yourself with tricks such as max66 proposed...

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.

Currying for templates in C++ metaprogramming

This is more of a conceptual question. I'm trying to find the easiest way of converting a two-arg template (the arguments being types) into a one-arg template. I.e., binding one of the types.
This would be the meta-programming equivalent of bind in boost/std. My example includes a possible use-case, which is, passing std::is_same as template argument to a template that takes a one-arg template template argument (std::is_same being a two-arg template), i.e. to TypeList::FindIf. The TypeList is not fully implemented here, neither is FindIf, but you get the idea. It takes a "unary predicate" and returns the type for which that predicate is true, or void if not such type.
I have 2 working variants but the first is not a one-liner and the 2nd uses a rather verbose BindFirst contraption, that would not work for non-type template arguments. Is there a simple way to write such a one-liner? I believe the procedure I'm looking for is called currying.
#include <iostream>
template<template<typename, typename> class Function, typename FirstArg>
struct BindFirst
{
template<typename SecondArg>
using Result = Function<FirstArg, SecondArg>;
};
//template<typename Type> using IsInt = BindFirst<_EqualTypes, int>::Result<Type>;
template<typename Type> using IsInt = std::is_same<int, Type>;
struct TypeList
{
template<template<typename> class Predicate>
struct FindIf
{
// this needs to be implemented, return void for now
typedef void Result;
};
};
int main()
{
static_assert(IsInt<int>::value, "");
static_assert(!IsInt<float>::value, "");
// variant #1: using the predefined parameterized type alias as predicate
typedef TypeList::FindIf<IsInt>::Result Result1;
// variant #2: one-liner, using BindFirst and std::is_same directly
typedef TypeList::FindIf< BindFirst<std::is_same, int>::Result>::Result Result2;
// variant #3: one-liner, using currying?
//typedef TypeList::FindIf<std::is_same<int, _>>::Result Result2;
return 0;
}
Click here for code in online compiler GodBolt.
I think the typical way of doing this is keep everything in the world of types. Don't take template templates - they're messy. Let's write a metafunction named ApplyAnInt that will take a "metafunction class" and apply int to it:
template <typename Func>
struct ApplyAnInt {
using type = typename Func::template apply<int>;
};
Where a simple metafunction class might be just checking if the given type is an int:
struct IsInt {
template <typename T>
using apply = std::is_same<T, int>;
};
static_assert(ApplyAnInt<IsInt>::type::value, "");
Now the goal is to support:
static_assert(ApplyAnInt<std::is_same<_, int>>::type::value, "");
We can do that. We're going to call types that contain _ "lambda expressions", and write a metafunction called lambda which will either forward a metafunction class that isn't a lambda expression, or produce a new metafunction if it is:
template <typename T, typename = void>
struct lambda {
using type = T;
};
template <typename T>
struct lambda<T, std::enable_if_t<is_lambda_expr<T>::value>>
{
struct type {
template <typename U>
using apply = typename apply_lambda<T, U>::type;
};
};
template <typename T>
using lambda_t = typename lambda<T>::type;
So we update our original metafunction:
template <typename Func>
struct ApplyAnInt
{
using type = typename lambda_t<Func>::template apply<int>;
};
Now that leaves two things: we need is_lambda_expr and apply_lambda. Those actually aren't so bad at all. For the former, we'll see if it's an instantiation of a class template in which one of the types is _:
template <typename T>
struct is_lambda_expr : std::false_type { };
template <template <typename...> class C, typename... Ts>
struct is_lambda_expr<C<Ts...>> : contains_type<_, Ts...> { };
And for apply_lambda, we just will substitute the _ with the given type:
template <typename T, typename U>
struct apply_lambda;
template <template <typename...> class C, typename... Ts, typename U>
struct apply_lambda<C<Ts...>, U> {
using type = typename C<std::conditional_t<std::is_same<Ts, _>::value, U, Ts>...>::type;
};
And that's all you need actually. I'll leave extending this out to support arg_<N> as an exercise to the reader.
Yeah, I had this issue to. It took a few iterations to figure out a decent way to do this. Basically, to do this, we need to specify a reasonable representation of what we want and need. I borrowed some aspects from std::bind() in that I want to specify the template that I wish to bind and the parameters that I want to bind to it. Then, within that type, there should be a template that will allow you to pass a set of types.
So our interface will look like this:
template <template <typename...> class OP, typename...Ts>
struct tbind;
Now our implementation will have those parameters plus a container of types that will be applied at the end:
template <template <typename...> class OP, typename PARAMS, typename...Ts>
struct tbind_impl;
Our base case will give us a template type, which I'll call ttype, that'll return a template of the contained types:
template <template <typename...> class OP, typename...Ss>
struct tbind_impl<OP, std::tuple<Ss...>>
{
template<typename...Us>
using ttype = OP<Ss...>;
};
Then we have the case of moving the next type into the container and having ttype refer to the ttype in the slightly simpler base case:
template <template <typename...> class OP, typename T, typename...Ts, typename...Ss>
struct tbind_impl<OP, std::tuple<Ss...>, T, Ts...>
{
template<typename...Us>
using ttype = typename tbind_impl<
OP
, std::tuple<Ss..., T>
, Ts...
>::template ttype<Us...>;
};
And finally, we need a remap of the templates that will be passed to ttype:
template <template <typename...> class OP, size_t I, typename...Ts, typename...Ss>
struct tbind_impl<OP, std::tuple<Ss...>, std::integral_constant<size_t, I>, Ts...>
{
template<typename...Us>
using ttype = typename tbind_impl<
OP
, typename std::tuple<
Ss...
, typename std::tuple_element<
I
, typename std::tuple<Us...>
>::type
>
, Ts...
>::template ttype<Us...>;
Now, since programmers are lazy, and don't want to type std::integral_constant<size_t, N> for each parameter to remap, we specify some aliases:
using t0 = std::integral_constant<size_t, 0>;
using t1 = std::integral_constant<size_t, 1>;
using t2 = std::integral_constant<size_t, 2>;
...
Oh, almost forgot the implementation of our interface:
template <template <typename...> class OP, typename...Ts>
struct tbind : detail::tbind_impl<OP, std::tuple<>, Ts...>
{};
Note that tbind_impl was placed in a detail namespace.
And voila, tbind!
Unfortunately, there is a defect prior to c++17. If you pass tbind<parms>::ttype to a template that expects a template with a particular number of parameters, you will get an error as the number of parameters don't match (specific number doesn't match any number). This complicates things slightly requiring an additional level of indirection. :(
template <template <typename...> class OP, size_t N>
struct any_to_specific;
template <template <typename...> class OP>
struct any_to_specific<OP, 1>
{
template <typename T0>
using ttype = OP<T0>;
};
template <template <typename...> class OP>
struct any_to_specific<OP, 2>
{
template <typename T0, typename T1>
using ttype = OP<T0, T1>;
};
...
Using that to wrap tbind will force the compiler to recognize the template having the specified number of parameters.
Example usage:
static_assert(!tbind<std::is_same, float, t0>::ttype<int>::value, "failed");
static_assert( tbind<std::is_same, int , t0>::ttype<int>::value, "failed");
static_assert(!any_to_specific<
tbind<std::is_same, float, t0>::ttype
, 1
>::ttype<int>::value, "failed");
static_assert( any_to_specific<
tbind<std::is_same, int , t0>::ttype
, 1
>::ttype<int>::value, "failed");
All of which succeed.

Partial default specialization of multiple parameter template

Is there a way to extract a partial default specialization from the compiler?
Say that I have this two parameter template:
template<typename A, typename B>
struct X {
A a;
B b;
};
and I also have some code that makes use of a single parameter template, like this:
template<template<typename> class T, typename B>
struct make_T_of_B {
T<B> member;
};
I'd like to be able to say:
make_T_of_B<X<int>, double> dummy;
where X<int> is taken as a single parameter template. It would be equivalent to this template:
template<typename B>
struct Y {
int a;
B b;
};
which looks like how one would specialize X<int, B> without actually changing anything. It's in a way similar to a default specialization -- except that a default specialization doesn't produce another template but rather an actual type (in other words, it's always total).
I realize that I can cascade the template arguments
template<typename A>
struct Z1 {
// start from scratch
template<typename B>
struct Z2 {
A a;
B b;
};
// inherit from double template above
template<typename B>
struct X: ::X<A, B> {};
};
make_T_of_B<Z1<int>::Z2, double> dummy1;
make_T_of_B<Z1<int>::X, double> dummy2;
but I find that to be rather hard to read and not communicate my intentions clearly.
Thank you.
I misunderstood your question. All you want is a way to bind the first template parameter, which you can do easily like this:
template <typename T> using Foo = X<int, T>;
Now Foo<double> is the same as X<int, double>.
Without C++11-style aliases, you can achieve the same with a bit more boilerplate:
template <typename T> struct Foo
{
typedef X<int, T> type;
};
Now you use Foo<double>::type.
I'd use a trait:
template <typename> struct applicator;
template <template <typename> class Tmpl, typename T>
struct applicator<Tmpl<T>>
{
template <typename A>
using rebind = make_T_of_B<Tmpl, A>;
};
Now you can say:
applicator<X<int>>::rebind<double> dummy;
You can of course also move the second argument, A, into the main template:
template <typename, typename> bpplicator;
template <template <typename> class Tmpl, typename T, typename A>
struct bpplicator<Tmpl<T>, A>
{
using type = make_T_of_B<Tmpl, A>; // or "typedef make_T_of_B<Tmpl, A> type;"
};
bpplicator<X<int>, double>::type dummy;
This has the advantage that it works in C++03, too.

Generalized Mixins

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.