9

Can anyone tell what is wrong with this piece of code?

template<class X>
class C {
public:
    template<class Y> void f(Y); // line 4
};

template<class X, class Y>
void C<X>::f(Y y) { // line 8
    // Something.
}

int main() {
    C<int> c;
    char a = 'a';
    c.f(a);
    return 0;
}

Compilation:

$ g++ source.cpp 
source.cpp:8: error: prototype for ‘void C<X>::f(Y)’ does not match any in class ‘C<X>’
source.cpp:4: error: candidate is: template<class X> template<class Y> void C::f(Y)

I now that I can accomplish the task by declaring and defining the function at line 4, but what would be the consequences of declaring and defining the function at the same time compared to doing it separately? (This is not a discussion about declaring a function at header vs source file)

Note: I have seen this question but is seems that the only part that interests me was left apart =(

Community
  • 1
  • 1
freitass
  • 6,542
  • 5
  • 40
  • 44

3 Answers3

18

The compiler already tells you the answer. The class C is a template with one parameter, and the member function f is a template member function, and you have to define it in the same way:

template <class X>
template <class Y>
void C<X>::f(Y y)
{
    // Something.
}

If you define the function at the declaration site, you'll implicitly declare it inline; that's about the only difference practically. There may be stylistic considerations, of course, e.g. never to put function definitions inside class definitions.

As you rightly observe, you will still have to provide the definition in the header file, since you will need to instantiate the template whenever you use it, and thus you need access to all the definitions.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Nice answer, thanks! One more thing: why @"Johannes Schaub - litb" says at the accepted answer of the question linked at the note that this practice (at least I think that he was referring to "template<> template<>") is not correct? – freitass Aug 10 '11 at 17:56
  • @Freitass: I'm not sure what you're referring to (can you be more specific?), but the linked question is about *template specialization*, which you aren't doing in your situation. – Kerrek SB Aug 10 '11 at 17:58
  • Well, [this](http://stackoverflow.com/questions/5512910/explicit-specialization-of-template-class-member-function/5513109#5513109) is the answer and I'm asking about the first line of the answer and the first chunk of code. – freitass Aug 10 '11 at 18:06
  • @Freitass: Again, that answer is about *specializing* the template parameter (the OP wanted to specialize the member template but not the class itself). How does this apply to you? – Kerrek SB Aug 10 '11 at 18:14
  • I just thought because both are related with template classes with template functions. Thanks for the `inline` part of your answer too (and again =D). I didn't have a clue about that. – freitass Aug 10 '11 at 18:27
2

The error tells you exactly, your code should look like this:

template<class X>
class C {
public:
    template<class Y> void f(Y); // line 4
};

template<class X> template<class Y>
void C<X>::f(Y y) { // line 8
    // Something.
}

int main() {
    C<int> c;
    char a = 'a';
    c.f(a);
    return 0;
}

Your class is not defined as template<class X, class Y>

RageD
  • 6,693
  • 4
  • 30
  • 37
-1

As an aside, it's preferable to use the keyword 'typename' instead of 'class' inside a template argument list.

Harry Seward
  • 147
  • 1
  • Yeah, I've read that too. But there's so many people using class.. I don't want to swim against the tide (at least not for this reason :P) – freitass Aug 10 '11 at 18:00
  • 3
    This should probably be a comment, not an answer. Also, I'm not agreeing or disagreeing with you, but you should probably back your statement up with some facts as to why use of 'typename' is preferable to 'class'. – andand Aug 10 '11 at 18:03
  • @andand: I coudn't agree more. – freitass Aug 10 '11 at 18:31
  • http://stackoverflow.com/questions/213121/c-use-class-or-typename-for-template-parameters – Harry Seward Aug 10 '11 at 18:43
  • is 'int' a class ? No. Will it be accepted as a template argument ? Yes. Is that ambiguous ? Yes. Can you prevent it ? Yes. Use 'typename'. – Harry Seward Aug 10 '11 at 18:46
  • Many people prefer `class`. `typename` can legitimately appear with its other meaning in a template parameter list. At least `class` is unambiguous. Inside a template `class` just means "type". The standard almost universally uses `class`, not `typename`. – CB Bailey Aug 11 '11 at 11:02