First, I have a template class:
template <typename T>
class Component;
Then I would like to create a class that can hold an arbitrary set of Component<T>'s as members, e.g. for N=2:
template <typename T, typename U>
class Aggregate
{
private:
Component<T>* m_comp1;
Component<U>* m_comp2;
};
At first glance, this looks like using variadic template would be a natural application.
template <typename... Comps>
class Aggregate
{
// what should go here for me to get Component<Comp1>, Component<Comp2>, ...?
};
However, I am unable to write the code that would essentially allow me to go from T, U, ... -> C<T>, C<U>, .... Currently, I have this achieved by creating a partial specialization for each N=1,2,3,4,... case, but this yields a lot of duplicated boilerplate code (and I would like to avoid having to write the Aggregate class to take in the template parameters directly as <Comp<T>,Comp<U>,...>). Is there a way to achieve the above? Thank you for any feedback/help in advance.
try using a tuple:
template <typename... Comps>
using Aggregate = std::tuple<Component<Comps>*...>;
There's no simple solution. Use std::tuple. Otherwise you'd need to reimplement it yourself, which is not trivial.
Related
A class ExpectTTs takes a number of template template parameters:
template< template<typename> class... TT >
struct ExpectTTs {};
Another type requires two template parameters. I need to fix one and pass the rest to ExpectTTs.
Currently I'm using this solution:
template< typename T >
struct TwoTs {
template< typename U >
struct Inner {};
};
ExpectTTs< TwoTs<int>::Inner >
Is it possible to change something so that I can pass a simple template instantiation like TwoTs<int> to ExpectTTs?
In several points in my codebase I have expressions like ExpectTTs< A, B, C<int>::Inner, D, E<int,int>::Inner, F<void>::Inner > and it seems unnecessary hard to read and write.
Any C++ version is fine.
If you have a template taking two parameters you cannot only specify one and obtain a template template. That is simply not possible. You also cannot create a template template alias as you can create a template alias with using. C++ does not make it easy to work with template templates, you can basically only use them when you fully instantiate them or when you pass them as a parameter to a template.
You also cannot get ExpectTTs really working with both template template parameters and type template parameters, since C++ strictly distinguishes between them (otherwise you could do something like let ExpectTTs extract the inner type). Maybe you could let ExpectTTs only take type template parameters, and make also A, B, and D have an Inner template while themselves being types, so you can let ExpectTTs always do the work for extracting the Inners. But then of course, you wouldn't be able to pass STL-templates like std::optional directly.
One small thing you could (in my opinion) improve in your design is using something like this:
#include <utility> // For the example
#include <optional>
template<template<class> class...>
struct ExpectTTs {};
template<template<class...> class TT, class T>
struct bind {
template<class U>
using bound_t = TT<T, U>;
};
ExpectTTs<std::optional, bind<std::pair, int>::bound_t> e{};
It's maybe even more verbose, but it does not need the intrusive Inner type and returns exactly the template template you want and not some other stand-in.
I have a scenario where class template seems to work for most cases, but some classes will need to define an extra variable/method for specific typename. Can I achieve this using templates only or should I use inheritance?
Sounds like you want to create a specialization. I arbitrarily chose std::vector as a type for when you wanted special behavior.
template <typename T>
struct Foo
{
// Stuff for most Types
};
template <typename T, typename A>
struct Foo<std::vector<T, A>>
{
// Stuff when the type is a std::vector of some types
};
Note that any common code will have to be duplicated in the specialization, or you may want to use a base class to represent the implementation - I suggest private inheritance if you choose that route.
I am new to template programming and I have two questions...Hopefully someone can help me.
I am trying to use variadic templates to generate a new input to another variadic template.
In other words, I have a class
template <std::size_t N, std::size_t... M>
class Class1 {
}
I want to use the integer values represented by N,M to generate a new set of std::bitset type inputs to another templated class
template <typename T, typename... Ts>
class Class2 {
}
So for example if I use Class1<10,20,25> I want inside the body of Class1 to
create a
Class2<std::bitset<10>, std::bitset<20>, std::bitset<25>>
variable. Is there a simple way to do this using C++11?
My second question then is how can I abstract this even more so that the unpacking is not specific to the std::bitset class?
Is there a way to modify the Class1 template definition so that I can expand some arbitrary templated class that I develop instead of std::bitset?
You might write something like:
template <std::size_t N, std::size_t... M>
class Class1 {
template <template <typename, typename...> class C,
template <std::size_t> class inner>
using rebind_with_type = C<inner<N>, inner<M>...>;
};
And then
Class1<10, 20, 25>::rebind_with_type<Class2, std::bit_set>
// -> Class2<std::bit_set<10>, std::bit_set<20>, std::bit_set<25>>
And if call it with dependent name, don't forget typename/template:
typename Class1<N, M...>::template rebind_with_type<Class2, std::bit_set>
// -> Class2<std::bit_set<N>, std::bit_set<M>...>
I find you can think of the ... operator on parameter packs in this way:
f(g(Xs)...);
will expand to
f(g(Xs1), g(Xs2), ..., g(Xsn));
for any operations f and g. Really all it is doing is adding a comma seperated list of g applied to each of the parameters provided. The ... defines where it should begin the expansion
These operations can be for types or values, so in your case our f is Class2<...> and our g is std::bitset our type would look like
Class2<std::bitset<N>, std::bitset<M>...>
The first one needs to be explicitly added since it's not part of the parameter pack ofcourse.
The other answers are excellent but let me give you an even more generic version of the accepted answer. You basically create a using alias that takes two templates, the first is the class that will hold the class templates as template parameters, and the second the template (like bitset) that you want to pass types to.
template<template<class...> class Y, template<class...> class Z, class... Ts>
using fold_types_into_t = Y<Z<Ts>...>;
template<template<class...> class Y, template<auto...> class Z, auto... Vs>
using fold_values_into_t = Y<Z<Vs>...>;
template<class,class...>
struct Class2;
template <std::size_t N, std::size_t... M>
class Class1 {
// Class2<std::bitset<10>, std::bitset<20>, std::bitset<25>>
using T=fold_values_into_t<Class2, std::bitset, N, M...>;
};
There could also be added support for classes that take values as well as types.
In C++ there are 2 template types (to my knowledge): template classes and template functions. Why is it not possible to have a template of template? (be it class, or function, or other template). Has it ever been considered in standards? Does it break C++ syntax/spirit in a way?
I know it may sound crazy, and it's easy to get around.
What is possible with C++:
template<bool b>
class TemplateDependingOnBool
{
public:
template<typename T>
class TheTemplateWeWant{};
}
What would be great:
template<bool b>
template<typename T>
class TheTemplateWeWant{};
and call it in a policy-based style (that's where it's really interesting):
template<typename T, template<typename> class ThePolicy = TheTemplateWeWant<true> >
class Foo {};
The way it's possible to do now is to use:
template<typename T,
template<typename> class ThePolicy = TemplateDependingOnBool<true>::TheTemplateWeWant >
class Foo{};
which is not very elegant.
EDIT:
I know I can template on 2 parameters. The goal is to use the underlying template class (the templated template) as something by itself, be it in a template alias or a template template parameter (as shown in my example).
Policy-based design is a reference to Andrei Alexandrescu's Modern C++ Design, which is the main reason why the feature I'm asking might be useful (because templates are used as template parameters).
With C++11, you're wrong in assuming only two types of templates. There are also type aliases which allow
template <bool b, typename T>
class TheTemplateWeWant { ... };
template<typename T>
using ThePolicy = TheTemplateWeWant<true, T>
If I'm understanding what you're asking correctly (and I'm not entirely clear on your question), then you could write your template taking two parameters:
template <bool b, typename T>
class TheTemplateWeWant { ... };
add a metafunction to partially apply the bool:
template <bool b>
struct PartiallyWant {
template <typename T>
using type = TheTemplateWeWant<b, T>;
};
and then pass that as your policy:
template<typename T,
template<typename> class ThePolicy = PartiallyWant<true>::type >
class Foo { ... };
Foo<char, PartiallyWant<false>::type> foo;
So why not just layer the templates like you propose? The simple answer is that there's no reason to. If TheTemplateWeWant has two template parameters (bool b and typename T, regardless of whether it's an "inner" class or not), then we should express it as such. And if we want to only apply one type or the other, that's something that has fewer use-cases than a general template while also being solvable with just a few lines of boilerplate. Additionally, what if we had such a feature, and now I want to partially apply the T instead of the b? With a few lines of boilerplate I can again accomplish the same thing, but with the layering this would be impossible.
As far as i know you cand you simply that, and it works just as you want - class templated with 2 parameters.
template<bool b, typename T>
class TheTemplateWeWant{}; //valid in C++
What you're describing is partial binding of template parameters, just like std::bind can turn a binary function into a unary function.
For metaprogramming madness, there's Boost.MPL. They do have a template boost::mpl::bind.
I know this is a simple question but I just could not find the answer.
I am trying to do something like this but instead of with std::vector ultimately I want it to be std::shared_ptr or std::weak_ptr:
template <int dim, class ChunkClass, class PtrClass>
class BaseChunkWindow : public IChunkWindow<BaseChunkWindow<dim, ChunkClass, PtrClass>, IChunk<ChunkClass>> {
public:
...
private:
PtrClass< IChunk<ChunkClass> > ptr; <-- compiler doesn't like this line, however IChunk<ChunkClass>* works
};
It depends on what you are passing it to, if the template you're trying to instantiate takes as a parameter a class template accepting 2 (or in c++11 a variadic number of) types then you can pass std::vector to that. In most cases however, templates require types as parameters and you cannot pass the class template std::vector.
template <class T>
struct gimme_a_type{};
template <template <class,class> class T>
struct gimme_a_template{};
gimme_a_type<std::vector> //<-- does not compile, expected a type, got a template
gimme_a_type<std::vector<int> > //<-- compiles, expected a type, got a type
gimme_a_template<std::vector> //<-- compiles, expected a template, got a template that has the correct signature
gimme_a_template<std::vector<int> > //<-- does not compile, expected a template, got a type
In response to your edit, there are difficulties to using class templates as template parameters. Matching the number of parameters exactly is actually difficult to do when you have default arguments in the class template you're trying to pass (std::vector in our case).
Notice that the example above required a class template that takes 2 types, not just one. This is because std::vector takes two parameters, the second is just defaulted to std::allocator<T> for us.
The following example demonstrates the issue:
template <template <class, class> class Tem>
struct A
{
Tem<int> v; //<-- fails to compile on gcc, Tem takes two parameters
Tem<int, std::allocator<int> >; //<-- compiles, but requires a priori knowledge of Tem
};
template <template <class...> class Tem>
struct A2
{
Tem<int> v; //<-- This C++11 example will work, but still isn't perfect.
};
The C++11 example is better, but if someone passed a class that has as a signature template <class, bool = false> class A3 it fails again because A2 requires a class template that takes types and not a mix of types and non-types (false being the non-type template parameter in this example). So even though A3<int> would be a valid instantiation you couldn't pass that class to A2.
The solution there is to always use types in template parameter lists and use the std::integral_constant wrapper template to pass integral constants around.
There are a couple ways of doing it.
The limited way would be to use a template template parameter with just a limited number of parameters being passed, e.g. 3.
template<template<class,class,class> class Cont, class T, class V, class U>
void f(Cont<T,V,U>&& cont) {
//...
}
However that's pretty limiting and can be hard to manage if you decide to change it in the future.
So you can do it like so with the new Variadic Templates in C++11:
template<template<class...> class Cont, typename F, typename... Rest>
void f(Cont<F, Rest...>&& cont) {
//...
}
This would work on other containers or things and is probably much easier to manage.