Altering template template parameters in C++ - c++

I would like to design a class that creates internal types that are variants of types passed as template parameters. Something like the following, non-functional example:
template <typename T>
class BaseClass
{
public:
typedef T InternalType;
std::vector<InternalType> storage;
};
template <typename Base>
class Injector
{
public:
typedef std::pair<typename Base::InternalType, typename Base::InternalType> RefinedType;
Base<RefinedType> refinedStorage;
};
typedef Injector<BaseClass<int> > InjectedInt; // Should store vector<pair<int, int> >
Since Base is a fully-specified type, Base<RefinedType> refinedStorage; will fail to compile. Simply using a template template parameter won't work, as the refined type needs to be based on the nested template's parameter as well as its base type.
How can I implement this pattern of creating types based on both the fully-specified and base types of a template parameter?
EDIT: I would like this to be an arbitrary-depth composite, with multiple injector types performing a cascade of transformations. Thus, passing both the template template parameter and the base parameter becomes pretty unwieldy (particularly when it comes to dealing with the base case of the composite), and an ideal solution would use the more direct syntax.

I was able to achieve this by explicitly 're-declaring' the general template inside itself:
template <typename T>
class BaseClass
{
public:
typedef T InternalType;
std::vector<InternalType> storage;
template<class T2>
using Recur = BaseClass<T2>;
};
template <typename Base>
class Injector
{
public:
typedef std::pair<typename Base::InternalType, typename Base::InternalType> RefinedType;
typename Base::template Recur<RefinedType> refinedStorage;
};
typedef Injector<BaseClass<int> > InjectedInt; // Should store vector<pair<int, int> >

You could introduce a rebind template:
template <typename From, typename To>
struct rebind_1st;
template <template <typename... > class Cls, typename A0, typename... Args, typename To>
struct rebind_1st<Cls<A0, Args...>, To> {
using type = Cls<To, Args...>;
};
template <typename From, typename To>
using rebind_1st_t = typename rebind_1st<From, To>::type;
With which your Injector becomes:
template <typename Base>
class Injector
{
public:
typedef std::pair<typename Base::InternalType,
typename Base::InternalType> RefinedType;
rebind_1st_t<Base, RefinedType> refinedStorage;
};

There is no need for a rebinding template, that over-complicates the situation. Simply have a template template type:
template<typename>
struct Injector;
template<typename T, template<typename> class Base>
struct Injector<Base<T>>{
using refined_type = std::pair<typename Base::InternalType, typename Base::InternalType>;
Base<refined_type> refined_storage;
};
You'll have to use a template specialization to get a concrete type from a template template.
This is used like so:
using injector_int = Injector<Base<int>>;
int main(){
injector_int i;
}
here's a live example

You can provide an external rebinder:
template <class Bound, class U>
struct rebinder;
template <template <class> class Binder, class B, class U>
struct rebinder<Binder<B>, U>
{
typedef Binder<U> type;
};
// Usage:
template <typename Base>
class Injector
{
public:
typedef std::pair<typename Base::InternalType, typename Base::InternalType> RefinedType;
typename rebinder<Base, RefinedType>::type refinedStorage;
};
[Live example]

Related

is_base_of of generic type

I'm trying to assert that template parameter would be derived from some base class. But base class is generic and in the context of assertion there is no difference between any specialization types.
How can I assert, that template parameter were derived from generic of any specialized type?
I'm trying to write it as
base_generic:
template<typename T> struct base_generic{};
derived_generic:
template<typename T> struct derived_generic : public base_generic<T>{};
class with assertion:
template<typename Tsource, typename Tderived_generic>
struct encoder {
static_assert(std::is_base_of<base_generic<typename>, Tderived_generic>::value);
};
This code compiles, but assertion fails
You may create a trait for that, something like:
namespace detail
{
template <template <typename > class C>
struct is_base_of_any_helper
{
template <typename T>
std::true_type operator ()(const C<T>*) const;
std::false_type operator() (...) const;
};
}
template <template <typename > class C , typename T>
using is_base_of_any =
decltype(detail::is_base_of_any_helper<C>{}(std::declval<const T*>()));
Demo
Note that it will fail with some edge cases such as:
multiple bases C<Tx>
private inheritance of C<T>.
From commentary of #PiotrSkotnicki
template <template <typename...> class Base, typename Derived>
struct is_base_of_template
{
using U = typename std::remove_cv<Derived>::type;
template <typename... Args>
static std::true_type test(Base<Args...>*);
static std::false_type test(void*);
using type = decltype(test(std::declval<U*>()));
};
template <template <typename...> class Base, typename Derived>
using is_base_of_template_t = typename is_base_of_template<Base, Derived>::type;
This solution works fine, example.
you can use static_assert.
See: http://en.cppreference.com/w/cpp/language/static_assert
So for example, if you have a base class
template< typename T >
class Base<T> {};
and the derived one
template< typename T >
class Derived : public Base<T> {};
with your use case
template< typename Tsource, typename Tstorage >
class Test
{
std::static_assert( std::is_base_of< base<T>, TStorage >::value );
}
It is not possible to get T without adding it as a template parameter.
But with a simple trick, you get it. You have to add a typedef to Derived:
template< typename T >
class Derived : public Base<T>
{
public:
typedef T value_type;
};
And you can use it inside of the static assertion.
template< typename Tsource, typename Tstorage >
class Test
{
std::static_assert( std::is_base_of< base<TStorage::value_type>, TStorage >::value );
}
Since Tstorage is a Derived, it has the value_type field.

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

Is T an instance of a template in C++?

Suppose I'm in a template and I want to know if a type parameter T is an instantiation of a particular template, e.g., std::shared_ptr:
template<typename T>
void f(T&& param)
{
if (instantiation_of(T, std::shared_ptr)) ... // if T is an instantiation of
// std::shared_ptr...
...
}
More likely I'd want to do this kind of test as part of a std::enable_if test:
template<typename T>
std::enable_if<instantiation_of<T, std::shared_ptr>::type
f(T&& param)
{
...
}
// other overloads of f for when T is not an instantiation of std::shared_ptr
Is there a way to do this? Note that the solution needs to work with all possible types and templates, including those in the standard library and in other libraries I cannot modify. My use of std::shared_ptr above is just an example of what I might want to do.
If this is possible, how would I write the test myself, i.e., implement instantiation_of?
Why use enable_if when simple overloading suffices?
template<typename T>
void f(std::shared_ptr<T> param)
{
// ...
}
If you really do need such a trait, I think this should get you started (only roughly tested with VC++ 2010):
#include <type_traits>
template<typename>
struct template_arg;
template<template<typename> class T, typename U>
struct template_arg<T<U>>
{
typedef U type;
};
template<typename T>
struct is_template
{
static T* make();
template<typename U>
static std::true_type check(U*, typename template_arg<U>::type* = nullptr);
static std::false_type check(...);
static bool const value =
std::is_same<std::true_type, decltype(check(make()))>::value;
};
template<
typename T,
template<typename> class,
bool Enable = is_template<T>::value
>
struct specialization_of : std::false_type
{ };
template<typename T, template<typename> class U>
struct specialization_of<T, U, true> :
std::is_same<T, U<typename template_arg<T>::type>>
{ };
A partial spec should be able to do it.
template <template <typename...> class X, typename T>
struct instantiation_of : std::false_type {};
template <template <typename...> class X, typename... Y>
struct instantiation_of<X, X<Y...>> : std::true_type {};
http://ideone.com/4n346
I actually had to look up the template template syntax, because I've basically never had cause to use it before.
Not sure how this interacts with templates like std::vector with additional defaulted arguments.
Best way to do it when dealing with a T&& is to make sure you remove_reference before doing the check, because the underlying type T can be a reference or a value type, and template partial specialization has to be exact to work. Combined with an answer above the code to do it could be:
template <
typename T,
template <typename...> class Templated
> struct has_template_type_impl : std::false_type {};
template <
template <typename...> class T,
typename... Ts
> struct has_template_type_impl<T<Ts...>, T> : std::true_type {};
template <
typename T,
template <typename...> class Templated
> using has_template_type = has_template_type_impl<
typename std::remove_reference<T>::type,
Templated
>;
And then you just enable_if your way to victory:
template <typename T>
typename std::enable_if<has_template_type<T, std::shared_ptr>::value>::type
f(T&& param)
{
// ...
}

Partial template template specialization

have this code:
template<typename T, template<typename, typename> class OuterCont, template<typename, typename> class InnerCont, class Alloc=std::allocator<T>>
class ContProxy {
OuterCont<T, InnerCont<T, Alloc>> _container;
};
typedef ContProxy<int, std::vector, std::list> IntCont;
But need to use T* instead of std::list<T> as InnerCont in some cases - like this:
template<typename T, template<typename, typename> class OuterCont, T*, class Alloc=std::allocator<T>>
class ContProxy {
OuterCont<T, T*> _container;
};
Is it possible to use partial specialization of 'template template' parameter for this case?
Or how to archive it with minimum headache..
It's often easier to template simply on the type. You can't really capture every situation with template templates - what if someone wants to use a container with six template parameters? So try something like this:
template <typename T, typename C>
struct ContProxy
{
typedef C container_type;
typedef typename C::second_type second_type;
container_type container_;
};
ContProxy<int, MyContainer<int, std::list<int>> p;
I would also go with kerrek's solution, but other than that, the best thing I could come up with was this.
The problem is that InnerCont is declared as template type in the base template, so you can't specialize it for raw pointer anymore. So you could create a dummy template representing a pointer and use that.
template<typename,typename> class PtrInnerCont; //just a dummy template that does nothing
template<typename T, template<typename, typename> class OuterCont, template<typename, typename> class InnerCont, class Alloc=std::allocator<T>>
class ContProxy {
OuterCont<T, PtrInnerCont<T, Alloc>> _container;
};
typedef ContProxy<int, std::vector, std::list> IntCont;
template<typename T, template<typename, typename> class OuterCont, class Alloc>
class ContProxy<T, OuterCont, PtrInnerCont, Alloc> {
OuterCont<T, T*> _container;
};
typedef ContProxy<int, std::vector, PtrInnerCont> MyCont;
You can't really do what you're doing already actually. Not in a standard way. The C++ containers don't take the same template parameters.
Do something like so:
template< typename T,
template<typename, typename> class OuterCont,
template<typename, typename> class InnerCont,
class Alloc=std::allocator<T>>
class ContProxy {
typename OuterCont<T, typename InnerCont<T, Alloc>::type>::type _container;
};
Then you can create different container generators like so:
template < typename T, typename A = std::allocator<T> >
struct vector_gen { typedef std::vector<T,A> type; };
Or your pointer one:
template < typename T, typename Ignored >
struct pointer_gen { typedef T* type; };

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.