1
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

Ken Bloom
  • 57,498
  • 14
  • 111
  • 168
thiagoh
  • 7,098
  • 8
  • 51
  • 77
  • 1
    Do you have a C++ book? Any [introductory book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) will teach you templates, and you aren't going to learn them by slash and hacking at them, unfortunately. – GManNickG Aug 11 '11 at 05:00
  • Changing the misleading title and tags. – iammilind Aug 11 '11 at 05:28
  • @iammilind: I'm changing it back. I think he actually wants to know how to do constrained generics like Java supports, and the mess of example code that he posted (with the confusion between plain `class T` and `template `) stems from an attempt to get this feature in C++. – Ken Bloom Aug 11 '11 at 05:50
  • I will clean up the tags a bit, specifically to remove the `java` tag though, because my editorial policy is that you don't put a `java` tag on a question when you know what you're doing in `java` but want to know how to do it in a different language. – Ken Bloom Aug 11 '11 at 05:51
  • @thiagoh: would you please tell us why you used the name `T` in `template ` (as opposed to some other letter like `Q`, `X`, or `Z`)? It would go a *long* way to helping us clarify some of the issues in your sample code. – Ken Bloom Aug 11 '11 at 05:54
  • @ken bloom see my coment at iammilind answer so you'll understand the problem.. – thiagoh Aug 12 '11 at 00:24

3 Answers3

4

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:

  1. 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.

  2. 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.)

  3. 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.

Ken Bloom
  • 57,498
  • 14
  • 111
  • 168
  • Exact the answer I am looking for, except I do not quite follow #2 structural typing(the scala way). I think what Scala does is very similar to what Java does, except Java uses use-site variance whereas Scala uses declaration-site variance[From Odersky's Scala book]. – leon Feb 26 '16 at 07:14
  • @leon: see https://www.safaribooksonline.com/library/view/scala-cookbook/9781449340292/ch19s04.html to understand what I was taking about. It's not a commonly used feature of the language, but it does demonstrate a language design possibility. – Ken Bloom Feb 28 '16 at 03:24
1

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.]

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • sorry for you all.. i found the problema by myself.. and when i came here again i saw this @iammilind answer.. so i realized the mistake was pretty stupid.. – thiagoh Aug 12 '11 at 00:19
  • @thiagoh, if the answer helped you then, you can accept it by ticking right mark below it :) – iammilind Aug 12 '11 at 04:59
0

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?

Chris Eberle
  • 47,994
  • 12
  • 82
  • 119