Reputation: 7388
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
Upvotes: 1
Views: 1260
Reputation: 58790
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.
Upvotes: 4
Reputation: 70030
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.]
Upvotes: 1
Reputation: 48795
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?
Upvotes: 0