I want to use my class with the template.
in main:
int main(void)
{
HexAdapter<vector> foo;
// maybe?
// HexAdapter<vector<Cell>> foo;
return 0;
}
I tried something like this
template <typename T>
class HexAdapter
{
public:
HexAdapter();
private:
T<T<Cell>> hexCells;
};
For the reason of this, Normally I used like this vector<vector<Cell>> hexCells But I want to work with all STL Containers with random access iterator.
You can achieve the HexAdapter<std::vector> syntax by relying on a template template parameter, i.e., a template parameter which is, in turn, a class template (or an alias template):
struct Cell { /* ... */ };
template<template<typename...> class Cont>
class HexAdapter {
Cont<Cont<Cell>> hexCells;
/* ... */
};
The template argument to the class template HexAdapter (i.e., the argument to the Cont parameter) must be a class template itself (e.g., std::vector or std::deque):
auto main() -> int {
HexAdapter<std::vector> foo;
HexAdapter<std::deque> bar;
}
Related
Situation
I'm trying to implement a container that holds a specific data type - let's call it C. The container(let's call it B) is an inner class of A. I'm trying to declare the template but am running into compiler issues and am not sure what I should do.
Attempts
template <typename T<C>>
class A
{
class B
{
typedef std::unique_ptr<T> containerPtr;
private:
containerPtr container;
}
}
typedef std::shared_ptr<A<std::vector<C>>> somePtr; // Error!
The error is:
struct C
type name is not allowed
template <typename T,U>
class A
{
class B
{
typedef std::unique_ptr<T<U>> containerPtr;
private:
containerPtr container; // But does it contain C or some other type now?
// We have to do a check - what's the best approach?
}
}
typedef std::shared_ptr<A<std::vector<C>>> somePtr;
What is the best approach in this situation?
If you know for a fact that T is a template container storing some type C, then you don't need to specify C anywhere and can just templatize over T:
template <typename T>
class A {
class B {
/* Use the type name T however you'd like. */
};
};
This works because T has to be the name of a complete type, so if you do something like
A<std::vector<int>>
then T is std::vector<int> and any time you use T it will specifically be a std::vector of ints and not of any other type.
On the other hand, if you want the client to provide the name of a template class and then forcibly instantiate it with your choice of C, you can use template template arguments, like this:
template <template <typename...> class T>
class A {
class B {
typedef std::unique_ptr<T<C>> containerPtr;
/* ... use containerPtr ... */
};
};
This asks the user to give you a template type, so you'd write something like
A<std::vector> myObject;
and your A template will then instantiate std::vector using the type C.
I am trying to inherit the std::vector class template into my membvec class template as public. And I want to use it as e.g. say membvec<float> mymemb(10) with the intention of creating my membvec variable mymemb containing 10 elements.
But I can't figure out how to write the templatised declaration of the public inheritance. What I am doing is the following, but all in vain.
template <typename T, template <typename T> class std::vector = std::vector<T>>
//error above: expected '>' before '::' token
class membvec: public std::vector<T>
{
const membvec<T> operator-() const; // sorry the previous version was a typo
//error above: wrong number of template arguments (1, should be 2)
...
};
I think you're looking for something like the below, but seriously don't do it. If you ever pass your class as its parent std::vector, there is no virtual interface to allow your class to provide any benefit whatsoever. And if you don't need to substitute for a std::vector then there's no need to inherit from it. Prefer free function algorithms or containing the std::vector as a member in your class instead.
#include <vector>
template <typename T>
class membvec: public std::vector<T>
{
// Don't need <T> in class scope, must return by value.
membvec operator+() const;
};
int main()
{
membvec<int> foo;
}
Perhaps you want something like this:
#include <vector>
template <typename T, template <typename T, class Allocator> class Vec = std::vector>
class membvec: public Vec<T, std::allocator<T>>
{
public:
// This is the signature in your question, but it's questionable.
const membvec<T, Vec> &operator+(int x) const
{
// You obviously want to change this.
return *this;
}
};
You can then use it regularly:
int main()
{
membvec<char> foo;
foo + 3;
}
I have a situation where I have nested structs like this:
struct A
{
struct B
{};
};
And I have some template code that needs to know the OUTER type (in this case, 'A').
So I'm trying to write a template function that can infer the outer type, and it looks like this:
template<typename T>
void func(typename T::B item)
{}
int main()
{
A::B item;
func(item); // Error here because "candidate template ignored: couldn't infer template argument 'T'"
return 0;
}
It doesn't compile, and the reason is given in the comment above.
Now, I could of course simplify the template to something like this, but as you can see below it does not satisfy my requirements of knowing the "outer" type, which is A.
template<typename T>
void func(typename T item)
{
// Oops, I now have the complete type of A::B but I have a
// specialized function that needs the A without the B as the type parameter
someOtherFunc<???>(...); // The ??? needs to be type A only, without the B
}
You could add a typedef A outerType; to your class B.
Then the implementation of func might be:
#include <iostream>
struct A{
struct B {
typedef A outerType;
};
};
template <class T>
void func( T f)
{
typedef typename T::outerType outerType;
outerType a;
someotherfunc(a);
}
int main ()
{
A::B item;
func(item);
return 0;
}
Then of course every inner class you have should name its outer Type outerType to make func work out the outer Type.
I am forgetting the syntax in this moment. Can someone please help? Basically below is what I am trying to do. I don't mind to set it up to take two template arguments if needed meaning runSchedule<SchedT, TaskT>() if this is easier. Also if you could comment on how to get the using alias to work for scheduler_type and scheduler_type::task_type to be recognized as types within the function.
#include <iostream>
class TestTask {
public:
int x;
};
template <typename TaskT>
class TestScheduler {
public:
typedef TaskT task_type;
int y;
};
template <template<class> class SchedT>
void runSchedule() {
typedef SchedT scheduler_type;
scheduler_type sched;
scheduler_type::task_type task;
}
int main() {
runSchedule<TestScheduler<TestTask> >();
}
You don't need a template template-parameter for what you're trying to do.
template < class SchedT>
void runSchedule() {
typedef SchedT scheduler_type; // <-- typedef syntax was backwards
scheduler_type sched;
typename scheduler_type::task_type task;
// ^^^^^ need typename keyword when referring to nested dependent type
}
The template<class> class SchedT in your template function argumets?
Replace with class SchedT.
The earlier syntax is for passing the template, the later a class generated by the template.
If I have a template class with a default template type, I have to write the template angle brackets. Is it somehow possible to avoid this?
Example:
template <typename T=int>
class tt {
public:
T get() { return 5; }
};
...
tt<> t; // how to avoid <>
std::cout << t.get() << std::endl;
Until now i've did this by a separate namespace and redeclaring the class:
namespace detail_ {
template <typename T=int>
class tt {
public:
T get() { return 5; }
};
}
class tt : public detail_::tt {}
...
tt t;
std::cout << t.get() << std::endl;
The problem is, if I want to use the class with an other type I have to go over namespace detail_. Is there another solution, which I didn't see yet.
... if I want to use the class ...
This is a common source of confusion. A class template is not a class, but a template from which classes are generated. The angle brackets is what tells the compiler that you want to generate a class out of the class template with the given template arguments, without the angle brackets what you have is a template.
template <typename T = int>
struct TemplateClass { /*...*/ };
template <template <typename> class T>
void f() {
T<int> t; // ...
}
template <typename T>
void g() {
T t; // ...
}
f<TemplateClass>(); // Accepts a template with a single type argument
g<TemplateClass<> >(); // Accepts a type, that can be generated out of the template
The language does not allow the coexistence of a template and a type with the same name in the same namespace, so the answer is that it cannot be done. You can create a type alias but you will have to give it a different name.
You can use typedef...
typedef tt<> tt_;
And then simply use tt_.
Since C++17, because of class template argument deduction, things have changed.
tt and tt<> are not the same thing: types and class templates were different and continue to be treated differently.
Anyway in simple scenarios like the one in your example, C++17 assumes what you mean and the <> aren't needed anymore.
Further details:
Template default arguments (specifically https://stackoverflow.com/a/50970942/3235496);
Why is <> required when specifying a template class which has defaults for all its template parameters?