Given a template like
template<int dim> class Point { ... };
this template can be instantiated explicitly like
template class Point<0>;
template class Point<1>;
template class Point<2>;
template class Point<3>;
instead of instantiating every template individually like above, I would like to instantiate them recursively with one call like
template class RecursiveInstantiate<Point, 3>;
where RecursiveInstantiate<T, i> would instantiate T<i>, T<i-1>, ..., T<0>. Is it somehow possible to create such a class RecursiveInstantiate? If it is not possible, do you know a way to do it with the preprocessor?
In fact I am interested in generalizing this for classes with multiple template parameters likeNode<int i1,int i2,int i3> for all combination of i1,i2,i3 in {0,1,2,3}. But I hope to be able to work out this second part by myself.
Any advice, also an explanation why it is impossible what I want to achieve is appreciated.
Update: thank you for your comments so far. I see now more clearly where the problem really is. The line
template class Point<3>;
instantiates the template and exports its symbols to the object file. An instantiation of the form
template class RecursiveInstantiate<Point, 3>;
may instantiate the classes class Point<3>, class Point<2>, .... Apparently this only happens locally though. The templates are not exported to the object file. Maybe I will have to look for a solution using the preprocessor.
As I see now that I did not ask my question precisely enough in the beginning, I appreciate your answers and selected ones as correct.
Note: I am trying this on linux with g++/clang as compilers.
You could make a little Instantiator class:
template <unsigned int N> struct Instantiator
{
Point<N> p;
Instantiator<N-1> i;
};
template <> struct Instantiator<0>
{
Point<0> p;
};
Then simply add one explicit instantiation: template struct Instantiator<81>;
You can extend this idea lexicographically to any number of integral parameters.
As #Georg says, let's make it generic:
template <template <unsigned int> class T, unsigned int N> struct Instantiator
{
T<N> t;
Instantiator<T, N-1> i;
};
template <template <unsigned int> class T> struct Instantiator<T, 0>
{
T<0> t;
};
template struct Instantiator<Point, 82>;
You can do that like this:
template<int dim> struct Point {
static const int val = dim;
Point<dim - 1> p;
};
template<> struct Point<0> { ... };
That creates a template specialisation for the template parameter when it is 0 so the recursion stops there, and when you instantiate one like this:
Point<4>
It instantiates from Point<4> down to Point<0>. Then you can do
Point<4>::val
to access the value of that particular one.
Related
This is not a major code breaking issue, I'm just wondering if I'm missing some neat trick.
If I am writing a templated class, I may start like this:
// some_header.h
template <typename TypeParameter, size_t max_array_size>
class TemplatedClass
{
std::array<TypeParameter, max_array_size> MyTemplatedArray;
public:
TypeParameter do_something()
{
/* do something with TypeParameter and max_array_sizein here */
}
}
This is fine, but when I have less trivial templated examples, I tend to separate out the function definitions from the declarations, like so:
// some_header.h
template <typename TypeParameter, size_t max_array_size>
class TemplatedClass
{
std::array<TypeParameter, max_array_size> MyTemplatedArray;
public:
TypeParameter do_something();
/*
Many more function declarations
*/
}
template <typename TypeParameter, size_t max_array_size>
TemplatedClass<TypeParameter, max_array_size>::do_something()
{
/* do something with TypeParameter and max_array_sizein here */
}
/*
Many more function definitions, all with:
template <typename TypeParameter, size_t max_array_size>
TemplatedClass<TypeParameter, max_array_size>
at the start
*/
The aim of this would be to have a classic skeleton class definition that can easily be read by others at a glance. I don't mind doing this, but the annoying thing is when I want to modify the template parameters. What is one change in the first example, ends up being 1 + 2 * n changes in the second example!
So what I am wanting to know is: Is there a way to make the second example's template parameters more maintainable? Maybe something similar to a typedef/using or maybe some keyword I haven't heard of?
First a non-answer:
Suppose, /*do something*/ depends on the template parameters. In that case, having to fix the signature is the smaller issue. You need to fix the implementation.
The other case is that /*do something*/ does not depend on the template parameters. Then you can move the methods to a non template base class.
A more serious attempt to answer the question:
What if TemplatedClass would have only a single template parameter instead of many? Instead of using a bunch of template parameters for TemplatedClass you can use a single tag and definition of the actual parameters can be defered to traits:
#include <array>
template <typename Tag> struct value_type_impl;
template <typename Tag> using value_type = typename value_type_impl<Tag>::type;
template <typename Tag> constexpr int array_size = 123;
template <typename Tag>
class TemplatedClass {
std::array<value_type<Tag>, array_size<Tag> > MyTemplatedArray;
public:
value_type<Tag> do_something();
};
template <typename Tag>
value_type<Tag> TemplatedClass<Tag>::do_something() {
return {};
}
// the tag
struct foo_tag{};
// specializations for foo_tag:
template <> struct value_type_impl<foo_tag> { using type = int; };
template <> constexpr int array_size<foo_tag> = 123;
int main() {
TemplatedClass<foo_tag> tc;
}
Now the burdon is on the user of the template to define one tag and then specialize the required traits for that tag. Though, the method definition has only a single template parameter that does not need to change when more "parameters" (traits) are added or removed. Of course you still need to fix the implementation.
If you were looking merely for some syntactic sugar, I am not aware of something that would help without changing the template itself.
I want to create a class that accepts only certain types of template classes. I know that there exists template specialization, but I want my class to accept all templates that implement a specific function, search.
Let's say I have a class A as follows:
template<class T> //add a restriction that T implements bool search(T)
class A
{
T t;
//do something that uses T.search(T x)
if(t.search(x))
//Do something
};
So basically, I want to create a generic class that works for all classes that have the search functionality. Is there a way to do this?
I want to create a generic class that works for all classes that have the search functionality. Is there a way to do this?
By example, using decltype() as follows
template <typename T,
typename = decltype(std::declval<T>().search(std::declval<T>()))>
class A
{
};
The following is a full compiling example for a size() enabled class A
#include <string>
#include <type_traits>
template <typename T, typename = decltype(std::declval<T>().size())>
class A
{
};
int main()
{
A<std::string> as;
//A<int> ai; // compilation error
}
There is a drawback in this solution: you can hijack it explicating the second template parameter; by example, the following code compile
A<int, void> ai;
To avoid this problem you can use partial specialization as follows
template <typename T,
typename = decltype(std::declval<T>().search(std::declval<T>()))>
class A;
template <typename T>
class A<T>
{
};
Consider the following:
template <class...>
struct MyT;
template <class T>
struct MyT<T> {};
template <template <class> class TT = MyT> struct A {}; // fine
using B = A<MyT>; // does not compile
int main() {
return 0;
}
When MyT is used as a default argument of A, the compiler (g++ 5.4.0) is happy. However, when it is used to instantiate A, the story is different:
temp.cpp:19:16: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class> class TT> struct A’
using B = A<MyT>;
^
temp.cpp:19:16: note: expected a template of type ‘template<class> class TT’, got ‘template<class ...> struct MyT’
I can fix it by introducing an alias:
template <class T>
using MyTT = MyT<T>;
using B = A<MyTT>; // fine
The question: what is the reason for the error and is there a solution without introducing an alias?
EDIT Please note that A is declared to have a template template parameter as shown and that is not given for change.
You cannot do that and you cannot use such a type as a default parameter. The fact that it seems to be accepted as long as you don't rely on it doesn't mean that the default parameter is a valid one.
Consider the following code that explicitly uses the default type:
template <class...>
struct MyT;
template <class T>
struct MyT<T> {};
template <template <class> class TT = MyT> struct A {}; // fine
int main() {
A<> a;
return 0;
}
The error is quite clear:
template template argument has different template parameters than its corresponding template template parameter
Partial specializations are not taken in account in this case, thus the two declarations differ.
You should either declare A as:
template <template <class...> class TT = MyT> struct A;
Or declare somewhere a type that is constrained to a single argument, as an example by means of an using declaration as you did.
First, the default argument doesn't work either.
Second, template template arguements are a strange beast. It would make sense if a template template argument would take anything that could be instantiated with the signature described in the template template argument.
That is not how it works.
Instead it works the other way around.
template<template<class...>class Z> struct foo {};
template<template<class >class Z> struct bar {};
template<class...>struct a{};
template<class >struct b{};
foo will accept a or b.
bar will accept only b.
The correct response to this, once you understand it, is "what the hell?". If you aren't responding "what the hell" back up and see if you can understand it. This basically works backwards from typical typing for arguements in C++; it behaves more like a return type than an argument. (Learn the terms contravariance and covariance if you want to see some of the language that lets you talk about this directly)
This is quite non-intuitive, and why it works this way exactly would involve tracking down the pre-history of C++.
But, as a benefit, a template<class...>class argument is in effect an "any template that only takes type parameters". I find this highly useful.
As a downside, template<class>class arguements are almost completely useless.
Tl;dr: make your template<template parameters be template<template<class...>class, and metaprogram only with templates that only take types. If you have a template that takes values, write a type wrapper that replaces a requirement for a std::size_t X with a std::integral_constant< std::size_t, X >.
Forgetting for a moment the question of "Why would you do this?",
the first version would work if you hadn't done any template specialization.
template <class T>
struct MyT { };
template <template <class> class TT = MyT> struct A
{};
using B = A<MyT>;
With template specialization, the compiler must determine the best match, but since you haven't ever actually provided any template arguments it's ambiguous.
When you introduce MyTT you are using a single template argument, and the compiler is smart enough to see that you have a specialization when there is only one arg:
template <class T>
using MyTT = MyT<T>;
It chooses the specialization instead of the variadic version in this case.
But now we circle back to the grand question... why? Unless within A you're always instantiating MyT with a specific class, it's pointless to use A at all:
template<template<class> class TT = MyT> struct A
{
// use an instance of TT??
TT<int> myInstance; // forced to choose `int`
};
I would like to split your question into 2 parts.
A) Consider the template of your structure is simpler
template <class T>
struct TestStruct {
};
template <
template <class>
class TT = TestStruct
>
struct A
{
int a; // sorry to modify this. This help to show how it works
};
int main() {
A< TestStruct > b;
b.a; // it works!
return 0;
}
It works because of the template class TT only accept the template with < class... > template. The specializated class is not count on this ( because the underlying of it is still template < class ... > )
B) even you update your struct A to the template< class... > one, you still have one more problem. What is the template argument of TT? Please see the example below
template <class...>
struct MyT;
template <class T>
struct MyT<T> {
int a;
};
template <
template <class...>
class TT = MyT
// may be you need to add some more typename here, such as
// typename T1, ... , and then TT<T1> a;
>
struct A
{
TT<int> a;
// Here ! TT is a template only, do not have the template parameters!!!
};
int main() {
A< MyT > b;
b.a; // it works!!
return 0;
}
But, if you really cannot update the signature of those definitions, you can do a proxy class
template< class T >
struct Proxy : MyT<T>
{
};
I'm trying to create an alias to a template, rather than a type and I can't find the syntax to do it. Below is an example that demonstrates my problem. My guess is this is just something that can't be done, but I'm hoping someone can prove me wrong. If it can't be done, is there some underlying reason it doesn't make sense to do this, or is it just not implemented?
template <class S>
class Down;
template <class S>
class Up {
template <class S1>
using Opposite = Down<S1>;
};
template <class S>
class Down {
template <class S1>
using Opposite = Up<S1>;
};
template <template <typename> class Direction>
void oneDirection() {
//Call another function here that uses the template argument as a template
}
template <template <typename> class Direction>
void bothDirections() {
oneDirection<Direction>();
oneDirection<Direction::Opposite>(); //This doesn't compile
}
int main() {
bothDirections<Up>();
}
In Direction::Opposite, Direction:: is a nested-name-specifier, and it can't indeed denote a class template (you'd need to give it the required template arguments to make it a template specialization).
I suppose one reason to not allow that form is that class templates can have partial or explicit specializations, which can provide different members from the primary template, so the compiler needs to work with a specific specialization to be able to know exactly what's available in there.
You can work around this by using traits to associate the two templates:
template<class> class Up { };
template<class> class Down { };
template<template<class> class Direction> struct Direction_traits;
template<> struct Direction_traits<Up>
{
template<class S1> using Opposite = Down<S1>;
};
template<> struct Direction_traits<Down>
{
template<class S1> using Opposite = Up<S1>;
};
template<template<class> class Direction>
void oneDirection() {
//Do something here
}
template<template<class> class Direction>
void bothDirections() {
oneDirection<Direction>();
oneDirection<Direction_traits<Direction>::template Opposite>();
}
int main() {
bothDirections<Up>();
}
However, keep in mind that Direction_traits<Up>::Opposite is not the same template as Down, at least not yet - the language rules may change in the future, more details in this answer and its comments.
This could cause problems if you want to get back to Up from inside oneDirection<Direction_traits<Up>::Opposite> using the traits - there won't be a trait specialization defined for the alias template. Things would need to get a bit more complicated to allow such use; a possible solution is outlined in the answer quoted above.
I'd like to place a POD type constrain on type parameter T of class template A and then derive another class template B from the satisfactory A. Besides, B is supposed to have different implementation according to constancy of instance of A. The purpose of doing all this is about, well you know, for better type checking before runtime.
All I can figure out is a tentative definition of A
template <typename T, typename POD=void>
class A;
template <typename T>
class A <T, std::enable_if<std::is_pod<T>::value>::type>
{
//blah...
};
so that A can't be instantialized when passing non-POD type, as you might have noticed that partial parameterization does the trick like a type switch.
But I can't figure out how B could be defined. I presume it looks like the following
template <typename A?>
class B;
template <>
B<const A?> : public A?
{
//blah...
};
template <>
B<A?> : public A?
{
//blah...
};
Any brilliant idea?
PS: Personally I tend to be highly critical. But just post how you think this could be done anyway.
There is no brilliant idea if the specializations are going to be completely different. You have to go with this:
template <typename T>
class B;
template <typename T>
class B<const A<T>> : public A<T>
{
};
template <typename T>
class B<A<T>> : public A<T>
{
};
which is almost same as you've written yourself except ? symbol.
You can instantiate this class as:
B<A<int>> x; //it chooses the second specialization
B<const A<int>> y; //it chooses the first specialization
See online demo. Note that you've forgotten typename here:
typename std::enable_if<std::is_pod<T>::value>::type
I fixed that too.
If some code in the specializations are going to be same, then you could do some trick in order to share the common part, but I cannot suggest anything as I don't know what you're going to put in the specializations.