Say you have a sub class B which inherits from super class A. You want a function that can accept either A or B.
template <typename T>
void someFunc(T* pObj, bool someOtherArg)
{
pObj->AnInheritMethod();
if (pObj->IsASub())
{
pObj->ANonInhertMethod();
}
}
When I compile this (Visual Studio 6) I get:
error C2065: 'pObj' : undeclared identifier
Am I way off base here?
You don't need a function template for this; the following will do just fine:
void someFunc(A* pObj)
{
pObj->AnInheritMethod();
if (B* pObjAsB = dynamic_cast<B*>(pObj))
{
pObjAsB->ANonInheritMethod();
}
}
Or, if you prefer to use your IsASub() member function instead of dynamic_cast:
void someFunc(A* pObj)
{
pObj->AnInheritMethod();
if (pObj->IsASub())
{
B* pObjAsB = static_cast<B*>(pObj);
pObjAsB->ANonInheritMethod();
}
}
Aside from the missing return type, I don't see anything obviously wrong with the code in your example; I don't have Visual C++ 6 installed to check.
You don't need templates for that, that is a free behaviour courtesy of polymorphism.
Edit: also if you write something like:
if (pObj->IsASub())
then there's maybe something wrong in your design. The method is supposed to work for any type in the derivation chain.
You're asking a question that is completely unrelated to the code and error that you included.
In order to have a function take an A or a class derived from A, all it needs to do is take a pointer or reference to A, e.g.
someFunc(A* pObj, bool someOtherArg);
or
someFunc(A& obj, bool someOtherArg);
It will work by virtue of inheritance. That's kind of the whole point of deriving classes from each other. The way you have written it with templates, it will work with any class that defines the three methods you use, whether or not it derives from A.
Now the error you posted is unrelated to this question but is bizarre. There's nothing wrong with the code you posted, but Visual Studio 6 is an ancient compiler; it's twelve years old and does not fully support modern ISO standard C++. This error may be an artifact of a sub-standard templating implementation in the compiler.
Related
In C# I can define this:
public interface BaseObject
{
int GetValue();
}
public class Test<T> where T : BaseClass
{
T BaseObject;
}
which means I know that I can alwaysa call BaseObject.GetValue() / BaseObject->GetValue(); because I know that the baseobject has this method.
Is there a similiar way to do this in C++? So that I can define an interface that multiple classes can inherit and a class that can take advantage of this.
Templates, which are even more powerful than C# generics (not to say they are necessarily better, just different).
template<class T>
class foo
{
public:
int whatever()
{
return obj.GetValue();
}
private:
T obj;
};
A separate class is created for each template argument you use. If you provide a template type which would result in an error you will know at compile time.
You're asking about C++ concepts, a way to specify requirements for template parameters. They were proposed during the work on C++11, but proved complicated enough that they weren't done in time. But they've just been delayed, not forgotten.
In the meantime, duck typing remains very powerful, and it will catch when you pass a template parameter that doesn't have the required interface. It just won't report the problem as neatly.
As a workaround, a simple way to check the constraint you showed takes advantage of the fact that pointer conversions are implicit only when upcasting:
public class Test<T> where T : BaseClass
{
static T* enforcement_helper = 0;
static BaseClass* enforce_inheritance_constraint = enforcement_helper;
};
Depending on how new your compiler is, you may need to put those lines inside a special member function (destructor is good, because it's almost always processed).
But you should only check constraints in order to improve error messages (by causing the failure in a clearly commented section of code). C++ templates are duck typed, and they will work with any template parameters that provide the required operations. No formal "interface" is required.
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.
class T : public std::string {
public:
T(char* s) : std::string(s){};
};
class X : public T {
public:
X(char* s) : T(s) {};
~X() {};
};
template <typename T> T doIt(const T arg);
int main(int argc, const char* argv[]) {
X s("initial string");
T s2 = doIt(s);
printf("out %s", s2.c_str());
}
T doIt(T arg) {
arg.append(" appended");
return arg;
};
What is the problem with my code.. the output is bellow...
1>Linking...
1>TemplateStuding1.obj : error LNK2001: unresolved external symbol "class X __cdecl doIt(class X)" (??$doIt#VXClass####YA?AVXClass##V0##Z)
1>D:\Programming\cpp\cpp-how-to-program\CppHowToProgram\Release\Test.exe : fatal error LNK1120: 1 unresolved externals
Once you get past the problem with the missing template <class T> on your definition of doIt (that others have already mentioned), you'll still want an answer to your question:
Is it possible to make a template argument <X extends T> like in Java?
The answer to this question is no. C++ does not have constrained generics like Java does. There was a proposal on the table to add something like this (but much different) called "concepts" in C++0x, but it was just too complicated and has been dropped.
In brief, there are 3 ways to do generics that are relevant:
Duck typing (what Ruby has). This is what C++ has now. If an class responds to all of the same methods as class T then it will fit the bill, even if it's not inherited from class T. In addition, if you try to pass class Z which is missing some methods that class T has, you'll never find out if the template doesn't try to call them. If the template does try to call them, then a compiler error will appear at the place where the template tries to call the missing method. (You'll find out which template instantiation caused the problem from a stack trace that the compiler will spit out explaining what templates it was trying to instantiate when it encountered the error.) You do get a compiler error in C++ (unlike Ruby, where it's a runtime error), but it's a complicated error message.
Structural typing (what Scala has). Concepts in C++ were intended to move in this direction. If an class responds to all of the same methods as class T then it will fit the bill, even if it's not inherited from class T. If that class doesn't respond to all of the same methods, it's an error, even if the template function doesn't try to call the missing method. Template errors are reported at the site of instantiation. (C++'s version of this would be more complicated because you can do declare operators on an object as free functions, but the basic idea is the same.)
Constrained generics (for lack of a better term -- what Java has). Any class passed to the template must be a subtype of class T. Having the same methods won't cut it unless there's real inheritance. Members of the C++ standardization commitee don't like this -- they prefer #2 over #1 (if they can work out all of the technical issues) and #1 over #3 -- so it will probably never appear in C++.
Would someone else please post an answer untangling this guy's use of class T in this example. He's using it in 2 different ways, and I'm not sure whether his use of T in template <class T> (as opposed to some other letter) was meant to specify a constraint on the types that could be passed. This may be a significant confusion. On the other hand, using T in both places may just be a careless error. I really can't tell.
Here is the problem:
template <typename T> T doIt(const T arg); // <---- declared but not defined
int main(int argc, const char* argv[]) {
//...
T s2 = doIt(s); // <------ it is calling above method (which is visible)
}
T doIt(T arg) { // <------ T is `class T`, not `template`, so different method
arg.append(" appended");
return arg;
};
Here when you define T doIt(T) after main(), you expect that you are defining the body of the above template method. Which is not true. You don't get compiler error because, coincidentally you have class T; which will pass the definition of T doIt(T).
If you intend to use template doIt then your definition should be as,
template<typename T>
T doIt(T arg) { // <------ T is now `template`; thus same method
arg.append(" appended");
return arg;
};
[Also note that, you get linker error because you din't have any real definition of template doIt and whatever definition you had below main() was not visible.]
Your compiler is complaining that you declared but never implemented doIt. All it is right now is a signature, and yet you're calling it like it's actually defined.
On a side note, what on earth does this error have to do with java? Or generics even?
I have a templated class that performs an action on the class that is given as template argument. For some of my classes I want to 'group' the functionality in one class, to make it easier for the caller. In fact the code looks something like this (names were changed):
template<typename T>
class DoSomeProcessing
{
public:
process(T &t);
};
class ProcessingFrontEnd : public DoSomeProcessing<CustomerOrder>, public DoSomeProcessing<ProductionOrder>
{
};
The problem is that when I call ProcessingFrontEnd::process with a CustomerOrder as argument, that the compiler complains about it.
I tried to reproduce the problem in a smaller test application. This is the code:
#include <vector>
class X : public std::vector<char>
, public std::vector<void *>
{
};
int main(void)
{
X x;
x.push_back('c');
return 0;
}
And indeed, if this is compiled, Microsoft's VS2010 compiler gives this error:
test.cpp
test.cpp(11) : error C2385: ambiguous access of 'push_back'
could be the 'push_back' in base 'std::vector<char,std::allocator<char> >'
or could be the 'push_back' in base 'std::vector<void *,std::allocator<void *> >'
test.cpp(11) : error C3861: 'push_back': identifier not found
I tested this test application with different types (char+void*, double+void*) and different arguments in the call ('c', 3.14), but the error message is always the same.
I tested this with VS2005 and VS2010 but I always get the same error.
Why can't the compiler determine the correct function to call? What makes this confusing for the compiler? Or is it just a bug in the Microsoft compiler?
EDIT:
If I explicitly add 2 push_back methods to my class, like this:
class X : public std::vector<char>
, public std::vector<void *>
{
public:
void push_back(char c) {}
void push_back(void *p) {}
};
The compiler doesn't complain anymore. So with these methods he can clearly distinguish between a character and a void-pointer. Why can't he do this if the two push_back methods are inherited from the parent?
This is by design. The compiler is not trying to resolve overloaded
functions because these are not overloaded
functions. The standard is really clear on that
(see 10.2.2). If the same name is found in two
different bases, it's an ambiguity, even if they
could be resolved correctly with the call (i.e. in
your case). Same-named functions in different classes will typically have quite different purposes and hence the selection between them should not be made on the basis of
their arguments. There are many good reasons not to
allow that, but here's one.
Imagine your class C derives from A and B and
these two base classes come from two different
libraries. If the author of B adds a new function
to the class, it may break the user's code by
redirecting a call from A::foo() to B::foo() if
the latter is a better match.
If you want the two functions to be treated in the same way that they would
be if part of a single class, then the best way to do it is with using
declarations in the derived class. Just add
using std::vector<char>::push_back;
using std::vector<void *>::push_back;
to the declaration of class X.
I believe you are running afoul of the C++ overloading rules which prohibit overloading across classes. You'd get the same results if your template classes were two separate classes, each with its own process(CustomerOrder) and process(ProductionOrder) member.
The workaround is explicit using statements inside your derived class, pulling in each overload from each of the template base classes.
How is the compiler supposed to know which process you want to call? There's two options. Do you want both, one, or the other?
You need to override process in the derived class.
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.