I'm trying to do a base template class which parameter T must be a structure.
When I use a variable declared as being of type T (both in the template class as in a class that extends it defining T) GCC fails to compile it:
GCC error: invalid use of incomplete
type ‘struct x'
Despite it working on VC I understand that it doesn't work because it shouldn't because the compiler isn't aware per the standard of the types that T represent.
Is there a way of making explicit that the type must be a structure?
What I'm doing in the code that works in VC is:
In the base class:
T* x
new T
sizeof(T)
In those that extend it:
x->member
Edit: I tried to take the relevant code. Here it is:
struct SomeStructureType
{
int memberA;
int memberB;
}
template <typename T> class Base
{
protected:
T* s;
void addMember(string name,void* offset);
Base()
{
s = new T;
}
};
class Extender : public Base<SomeStructureType>
{
public:
Extender()
{
addMember("memberA",&s->memberA);
}
}
Most (if not all) times the compiler complains about using an 'incomplete' type the problem resides in trying to use a forward declared class that has not been completely defined.
There are just so many things you can do with an incomplete type: define functions that take or return the type or references to it, define reference or pointer variables of that type... and others you cannot do: define variables of that type, create an object of the type, call any method or request any attribute from the type...
The question in the title can be dismissed; C++ classes and structures cannot be distinguished other than by source code inspection.
The explanation is quite confusing. There's apparently a message about struct x yet the example code contains not a single x. That tells me that you're not careful about matching up errors and source code. Once you do that, you often don't need StackOverflow anymore - you'll see the problem yourself.
There is nothing wrong with the code you've posted other than two missing semicolons after class/struct definitions: http://codepad.org/yfbHa8sO
The problem isn't related to the fact that T must be a structure. The problem is in that one of the structures (that I'm using in my code but was not created by me) is said to be incomplete by gcc. Anyway, I removed the class that uses this structure and other classes compile with the same base class. So, is up to me to fix it and what I assumed about the problem was wrong.
Related
How do lines (2) and (3) even compile in the following C++ class, given that this is a pointer, so should need -> notation to access fields (as seen in line (1))? (Source)
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
template <typename T>
class sptr_wrapper
{
private:
boost::shared_ptr<T> sptr;
public:
template <typename ...ARGS>
explicit sptr_wrapper(ARGS... a)
{
this->sptr = boost::make_shared<T>(a...);
}
explicit sptr_wrapper(boost::shared_ptr<T> sptr)
{
this->sptr = sptr; // (1)
}
virtual ~sptr_wrapper() noexcept = default;
void set_from_sptr(boost::shared_ptr<T> sptr)
{
this.sptr = sptr; // (2)
}
boost::shared_ptr<T> get_sptr() const
{
return sptr; // (3)
}
};
The line (2) is invalid. As you said, this is a pointer, we need to use -> instead of .
As the member of class template, sptr_wrapper::set_from_sptr is not required to be instantiated, until it's used. So you can add some code trying to call it, then you might get compile-errors as you expect.
This applies to the members of the class template: unless the member is used in the program, it is not instantiated, and does not require a definition.
The line (3) is valid; sptr refers to the member sptr, which has the same effect as this->sptr.
When a non-static class member is used in any of the contexts where the this keyword is allowed (non-static member function bodies, member initializer lists, default member initializers), the implicit this-> is automatically added before the name, resulting in a member access expression (which, if the member is a virtual member function, results in a virtual function call).
Would you believe that the reason this compiles is because nothing really gets compiled here?
The shown code defines a template.
A template does not become "real" until it instantiates a class. Only at that time the compiler gets a closer look at the template, and attempts to figure WTF it's doing.
Sure, when defining a template the compiler makes a half-hearted attempt to parse the template, but only barely enough to satisfy itself that the template consists of some plausibly-looking C++ code.
If you add some additional lines to the shown code you'll get the compilation errors you were yearning for:
class X {};
void foo()
{
sptr_wrapper<X> x;
boost::shared_ptr<X> y;
x.set_from_sptr(y);
}
And this produces the compilation errors you were looking for:
t.C:27:14: error: request for member ‘sptr’ in ‘(sptr_wrapper<X>*)this’, which is of pointer type ‘sptr_wrapper<X>*’ (maybe you meant to use ‘->’ ?)
27 | this.sptr = sptr; // (2)
Note that merely instantiating
sptr_wrapper<X> x;
isn't enough. You have to go full throttle and invoke the method in question, before it becomes "real" in the eyes of a C++ compiler, and it chokes on it.
It's true that I can quite think of any circumstance where "this.foo" might be valid C++ code, but I'm sure that somewhere in the 2000 pages that make up the current C++ standard, the exact details of what's going on gets spelled out in a very pedantic way.
And you might consider dropping a note to your compiler's bug tracker, a feature request to have your compiler issue a friendly warning, in advance, when it sees something like this.
I have a problem with the usage of a static class member size of a class SizeObj, which is used as template parameter for a template class SizeTemplate. See below the code snippet, which I reduced to the minimum.
In fact that code below ran well up to MS VS2008, but now the compilation fails
when compiling with VS2010. The following error messages are displayed:
error C2275: 'K' : illegal use of this type as an expression
error C2228: left of '.size' must have class/struct/union
It need to be said, that the compilation fails only, if the getSize method is
called at least once.
Please don't ask about the sense of the code below, as said I reduced it to the
essential minimum to explain. However, I need to admit that the
usage of the member 'size' is not very elegant due to several reasons, and maybe
there are lots of better solutions, but at the moment, I don't have any choice
to keep it like that.
Do you know what may be wrong here? Is it possible to solve that by build
settings or something similar? I didn't find yet anything suitable yet.
In the following posts it was easy, because an instance of class K is available, but for my problem, I don't know how to get that instance properly:
Illegal use of type in template
Simple templated function to convert std::vectors - "illegal use of this type as an expression"
//myTemplate.h
class SizeObj
{
public:
static const int size = 1;
};
template<class K>
class SizeTemplate
{
public:
int getSize();
};
template<class K>
int SizeTemplate<K>::getSize()
{
return K.size;
}
//main.cpp
int main(...)
{
SizeTemplate<SizeObj> sizeObj;
printf("size:%d", sizeObj.getSize());
}
Thank you a lot in advance!
tangoal
Unlike Java, in C++ you cannot use the dot operator on classes, you need use the scope resolution operator (i.e. ::) to get things from within the class scope (for example the size static variable), so replace return K.size with return K::size
Also marking the method to be constexpr is likely going to help here.
I have a c++ class such as the following:
class some_class {
protected:
decide_later some_variable;
public:
void some_random_function();
};
void some_class::some_random_function() {
decide_later another_variable;
}
The problem is that I don't know what variable type some_variable will be until I create an instance of the class. What I want to do is something like the following:
some_class class_instance(std::string);
And that would set decide_later to use std::string (or int, or double, or whatever it is told to use). In addition, it would be great if I could use decide_later as a variable type later on in other functions that are members of the class. For example, in the function some_random_function().
I have tried using boost::any to do this, but it seems to only work for numeric types. Besides, I think it would be more efficient if I could actually set the actual variable type.
Is this possible?
You are looking for templates. Declare your class like:
template <typename T> class some_class {
protected:
T some_variable;
public:
void some_random_function() {
T another_variable;
}
};
and instantiate it with:
some_class<std::string> class_instance();
If you know the type statically when you create the instance, you should use C++ templates and make the type a template parameter.
If you know it only dynamically (i.e. based on user input), you can either branch then and instantiate the template with different type parameters, or you can go for a completely dynamical solution (like boost::any or equivalent).
However, I believe that if you can't do this with templates then there's something wrong in your program design. The idea of C++ static typing is that types are known at compile time. Normally in object-oriented design you would use polymorphism instead of weak typing.
Sorry for this foolish question, but I'm quite new to C++.
I have a base class called AlertInfoBase in my project. It has some dozens of subclasses. Now I want to have a class template, which will have a method filter(). This method will always return a reference to AlertInfoBase. Here's the code:
template <class T>
class AlertInfoFilter
{
public:
AlertInfoFilter() { }
AlertInfoBase & filter(T & alertInfo)
{
return alertInfo;
}
};
As you can see, the method filter just returns the passed parameter. My goal is to create alternate implementations of filter() using template specialization, but this is not my problem/question right now.
The strange thing I'm facing is that, when I pass an instance of a class to filter(), which is subclassed from AlertInfoBase, everything works as expected. It returns same reference, but when I pass an instance of a class which doesn't implement AlertInfoBase, the project doesn't compile. Actually this is the kind of behavior I want to have, but some clarification why is this happening would be nice. Is the compiler smart enough to guess that I fill the method with incorrect parameter due to return type?
Thanks
P.S. I'm using MinGW compiler.
You can think of templates as a code generation mechanism. A particular instantiation of a template is identical in most ways to manually written code that just substituted the template argument where appropriate. In your example, if you instantiated AlertInfoFilter with a std::string (as an example of a class that does not inherit from AlertInfoBase), then the following code would be generated (approximately):
class AlertInfoFilter_string
{
public:
AlertInfoFilter_string() { }
AlertInfoBase & filter(std::string & alertInfo)
{
return alertInfo;
}
};
Clearly, this should not compile.
Yes, the compiler is exactly smart enough to know that. It's using the implicit conversion from child to base class when T descends from AlertInfoBase and isn't able to convert your T to the return type in other cases.
It would also work with a class that implemented operator AlertInfoBase& in an unrelated class but that would just add confusion so I don't suggest it.
filter takes a T as input and converts it to an AlertInfoBase. If T is now a type that is not a sub-class of AlertInfoBase, and does not offer a conversion, then the program cannot be compiled.
Actually, the compiler does something ver close to taking the code, substituting T for the actual argument and compiling the template. This happens once for every different T you use in your program.
When you pass eg. an int, you get:
class AlertInfoFilter
{
public:
AlertInfoFilter() { }
AlertInfoBase & filter(int & alertInfo)
{
return alertInfo;
}
};
which obviously doesn't compile.
I have two classes: one of them has an incomplete type, and the second needs to use that incomplete type. Is there any way to reference an "external type", in a manner similar to how you reference an external object?
Edit: Details about the structure of my classes.
Unfortunately I can't use pointers either. My code looks something like this:
class CompleteA {
private:
friend CompleteB;
struct IncompleteA;
boost::shared_ptr<IncompleteA> data_;
};
class CompleteB {
public:
void SomeFct(CompleteA& a) {
// I need to access a member of the incomplete type
a.data_->someMember;
}
};
I could have a separate header and source files pair but the that would be a bit of an overkill in my case. The incomplete type is just a struct with one member; I use it to hide the implementation. (However, if there's no other option, I will resort to having a separate header...)
About my use of friend, please ignore that and concentrate on what I'm asking help with. I've pondered about whether or not I should use friend here and I've come to the conclusion that using getters (instead of a friend) would expose the implementation.
Use forward declaration.
In your yourotherclass.h:
class IncompleteClass;
class YourOtherClass
{
IncompleteClass* member;
};
In your yourotherclass.cpp you will actually need to include the incompleteclass.h in order to be able to use the pointer.
Edit: responding to your details:
If you want to hide the implementation, create a separate (friend) class for that and reference that:
class CompleteAImpl
{
friend CompleteA;
// data, members, etc. that you intend to hide
};
class CompleteA
{
CompleteAImpl* priv; // or shared_ptr if you want
};
I think you wanted to do something like this. The problem with your implementation is that in order to reference a member a struct/class the compiler needs to to know the size of that member and the preceding members. You can cast your (a.data_ + sizeof(all preceding members)) to the type of someMember and dereference that; but it's an ugly and unsafe solution.
I couldn't really understand your question properly.
But from what I understand, I can only say that an incomplete type can be used as pointer only in your code.
struct A; //incomplete type, since it has not been defined yet!
A *pA; //okay - pointer to an incomplete type is allowed!
A a; //error - cannot declare an automatic variable of incomplete type!
I hope this information would help you finding the actual solution to your problem!
There is one very simple solution, if you only need access to someMember: provide a private getter, with an out of line definition.
class A {
private:
friend B;
int getSomeMember() const; // defined in .cpp
struct IncompleteA;
boost::shared_ptr<IncompleteA> data_;
};
class B {
public:
void SomeFct(A& a) {
a.getSomeMember();
}
};