second template question of the day, what a n00b:
I have a template class:
template <class T>
class foo{
private:
//...
T SubFoo;
//...
};
I also have a class called myClass. I would like to have objects of the kind:
foo<myClass> myObject;
But, and here's the problem, I would like to be able to get a pointer to myObject from myObject.SubFoo. That means that one of the members of the class myClass should be an instantiation of the template class foo.
So I can do:
class myClass{
//...
foo<myClass>* point2myClass;
}
However, it seems that this does not work because
./foo.h:103: error: ‘foo::SubFoo’ has incomplete type
When defining myClass, the program finds the line
foo<myClass>* point2myClass;
It goes to the defintion of foo and it finds:
T SubFoo;
but T, in this case myClass, has not yet been defined (that is what the program was doing!), so it doesn't know what T is, hence the error.
If I interchange the order of declarations, it will also fail because "foo" will not be defined.
How can I make this work??
Thanks a million!
The following code, should definitely work just fine. If your code is different, please specify where.
template < typename T >
struct A
{
T x;
};
struct X
{
A<X>* x;
};
int main()
{
X a;
}
Related
I've been struggeling with the following problem:
// this is in a header file
template <typename T>
struct Foo {
T x, y;
// ... other stuff
struct Bar {
int a, b;
// ... other stuff
void f() const;
};
Bar h() const
{ return { reinterpret_cast<int>(this->x), reinterpret_cast<int>(this->y) }; }
};
It's clear that Foo::h() needs to be implemented in the header file since it depends on the template argument.
But this is not the case for Foo::Bar::f().
I would like to implement this in a separate .cpp-file, since it only needs to compile once and so on.
Just as a note: I would like to keep this as a nested type for namespacing reasons.
Is there a nice way to do this ?
I dont't see why this shouldn't work, since Foo::Bar does not depend on the template argument at all.
Thank you very much !
Edit: fixed typo
I dont't see why this shouldn't work, since Foo::Bar does not depend on the template argument at all
This is not correct conclusion - the nested class has access to all names (private, protected, etc) to which the enclosing class has access, so depending on how the enclosing class is instantiated, the nested class has different surrounding context, thus Foo<int>::Bar and Foo<char>::Bar are not the same classes (to be precise - the nested class is part of the enclosing class definition, so without Foo<int>/Foo<char>, Bar doesn't exist, but since these are different classes, Bar under those classes are also different)
not sure what you mean by "namespacing reasons", but if you just want to access it like Foo<T>::Bar, you can use alias.
struct ChocolateBar {
int a, b;
// ... other stuff
void f() const;
};
template <typename T>
struct Foo {
T x, y;
// ...
using Bar = ::ChocolateBar;
Bar h() const { return { reinterpret_cast<int>(this->x), reinterpret_cast<int>(this->y) }; }
};
doesn't work with a normal class. The infamous
error: field 's' has incomplete type 'S'
struct S
{
struct N
{
S s;
};
};
int main()
{
S s;
}
Though why not? Doesn't make much sense. Why then the methods of S have a complete type. And methods of N have a complete type
struct S
{
struct N
{
N(){ S s; }
};
};
int main()
{
S s;
}
and so the moment where it should work but doesn't, works with template classes
template<class=void>
struct S
{
struct N
{
S s;
};
};
int main()
{
S<> s;
}
If it works with a template it should work with a normal class. Shouldn't it?
To create an object of a class the compiler needs to know the size of the class. If the class isn't fully defined yet (which it isn't until the closing }) then the size is unknown, the compiler can't know if there's more members or not, and can thus not be able to create instance of the class.
A template isn't a class in itself, it's kind of like a blueprint for a class that will be defined sometime in the future. That's why templates can be nested, because it's only a template not an actual class. The class is known when the template is instantiated, which is it when you do e.g. S<>, and by then the compiler can use the template to create the actual class.
As noted pointers to classes works, because the size of a pointer is known.
template<typename T> class SomeClass{
public:
enum SomeEnum{ SOME_FLAG};
};
SomeClass::SomeEnum some_enum = SomeClass::SomeEnum::SOME_FLAG; //NO
SomeClass<int>::SomeEnum some_enum = SomeClass::SomeEnum::SOME_FLAG; //NO
SomeClass<int>::SomeEnum some_enum = SomeClass<int>::SomeEnum::SOME_FLAG; //YES
This won't compile because
class SomeClass used without template parameters
Is there no way / workaround to use it without template parameter, kinda make that enum global for that class, so it doesn't depend on the parameter.
It's not that I can't type them but they can be long and complicated, the code will be harder to read and I can't use something like auto here.
(I'm new to templates so sorry if this question is lame.)
If you want to enclose your enum in a class definition for reasons (I cannot say what's the real problem), you can still introduce one more class that isn't a class template and contains the enum, then inherit from that with your class template. That's all.
As an example:
struct SomeBase {
enum SomeEnum { SOME_FLAG };
};
template<typename>
struct SomeClass: SomeBase {
// ...
};
Use this:
SomeBase::SomeEnum::SOME_FLAG;
Instead of this:
SomeClass::SomeEnum::SOME_FLAG;
Whenever you want to access the enum directly.
Something like the following remains valid anyway:
SomeClass<void>::SomeEnum foo = SomeClass<void>::SomeEnum::SOME_FLAG;
using MySomeClass = SomeClass<int>;
MySomeClass::SomeEnum foo = MySomeClass::SomeEnum::SOME_FLAG;
I want to add a static function to a template class that is accessible without passing template parameters first. Is that possible?
namespace foo {
template <typename T>
class bar {
public:
static void eggs();
};
}
foo::bar<some_t>::eggs(); // works
foo::bar::eggs(); // does not work
I would like to avoid moving eggs() to the foo namespace or to create a new namespace for it (eg. foo::bar_::eggs(), ugh).
No. That is not how template classes work. What you want to do is not possible in C++.
Remember that foo::bar does not name any type, but solely a template that can be used to create other types.
Besides using typedefs/type aliases (through using), you can perhaps have a non-templated base class for you templates, and then put your static members there. If you use public inheritance, changing the static member in any of the templated classes will change in all of them.
After experimenting with your code:
I want to add a static function to a template class that is accessible
without passing template parameters first. Is that possible?
namespace foo {
template <typename T>
class bar {
public:
static void eggs();
};
}
foo::bar<some_t>::eggs(); // works
foo::bar::eggs(); // does not work
I would like to avoid moving eggs() to the foo namespace or to create
a new namespace for it (eg. foo::bar_::eggs(), ugh).
I have come to the conclusion that, the first instance of
foo::bar<some_t>::eggs(); // works while
foo::bar::eggs(); // doesn't
Is due to the fact that when working with templates, anything within the class has to be relative to a specific object, even if you do not want the function to be. I even tried using function pointers and tried to save them to template class and without no avail I couldn't even get that to compile. I do not see much of an option for you in this situation. There maybe other tricks out there that someone might know, but not from what I can see.
You can make the template parameter optional and you can define a specialized template. Like this:
namespace foo {
template <typename T = void> class bar {
public:
static void eggs() { cout << "First there was the egg" << endl; }
};
template <> class bar<void> {
public:
static void eggs() {
cout << "Then there was the chicken... or was it?" << endl;
}
};
}
auto main() -> int {
foo::bar<int>::eggs(); // egg
foo::bar<>::eggs(); // chicken
return 0;
}
I know the title is a little confusing but I will try to explain what I mean.
So, think you have a class Foo and it has some template variables. It is something like :
class A
{
public:
A();
~A();
};
template <class T>
class Foo
{
public:
//These are my constructors.
Foo();
Foo(T);
Foo(T*, int); //This is for something else.
T var;
}
But in main function, I want to have something like this :
Foo<Foo<A>> multiFoos;
And Visual Studio says
"no default constructor exists for Foo<Foo<A>>"
So, I hope my question is quite clear and you can help me with this.
Thanks,