How can I declare and define a friend template function in a template class?

Discussion in 'C++' started by =?gb2312?B?wfXquw==?=, Jul 31, 2007.

  1. Hi folks,
    I am running into with such a question when I tried to declare and
    define a friend template function in a template class, here is the
    code snippet:

    #include <iostream>
    using namespace std;

    template<typename T>
    class Test {

    friend Test<T> index(Test<T>& start, Test<T>& end, Test<T>& step);
    };

    template<typename T>
    Test<T> index(Test<T>& start, Test<T>& end, Test<T>& step) {
    cout << "This is index is working\n";
    return Test<T>();
    }


    int main() {

    Test<int> start = Test<int>();
    Test<int> end = Test<int>();
    Test<int> step = Test<int>();

    Test<int> rslt = index(start, end, step);
    }

    When compiled with VC8.0, a linkage error araised:

    Test.obj : error LNK2019: unresolved external symbol "class TVEC<int>
    __cdecl index(class TVEC<int> &,class TVEC<int> &,class TVEC<int>
    &)" (?index@@YA?AV?$TVEC@H@@AAV1@00@Z) referenced in function _main
     
    =?gb2312?B?wfXquw==?=, Jul 31, 2007
    #1
    1. Advertising

  2. Áõê» wrote:
    > Hi folks,
    > I am running into with such a question when I tried to declare and
    > define a friend template function in a template class, here is the
    > code snippet:
    >
    > #include <iostream>
    > using namespace std;
    >
    > template<typename T>
    > class Test {
    >
    > friend Test<T> index(Test<T>& start, Test<T>& end, Test<T>& step);


    Since 'index' is a template, it has to be declared at the namespace level
    before it's declared here. Otherwise, this friend declaration refers to
    a non-template function.

    Take the declaration of 'index' from below (not the whole definition)
    and place it before the template definition. That will require the
    template itself to be *declared* before it, as well. I know, I know,
    it's a PITA, but that's what is required.

    > };
    >
    > template<typename T>
    > Test<T> index(Test<T>& start, Test<T>& end, Test<T>& step) {
    > cout << "This is index is working\n";
    > return Test<T>();
    > }
    >
    >
    > int main() {
    >
    > Test<int> start = Test<int>();
    > Test<int> end = Test<int>();
    > Test<int> step = Test<int>();
    >
    > Test<int> rslt = index(start, end, step);
    > }
    >
    > When compiled with VC8.0, a linkage error araised:
    >
    > Test.obj : error LNK2019: unresolved external symbol "class TVEC<int>
    > __cdecl index(class TVEC<int> &,class TVEC<int> &,class TVEC<int>
    > &)" (?index@@YA?AV?$TVEC@H@@AAV1@00@Z) referenced in function _main


    This is what your code should look like (I think):

    #include <iostream>
    using namespace std;

    template<typename T> class Test;

    template<typename T>
    Test<T> index(Test<T>& start, Test<T>& end, Test<T>& step);

    template<typename T>
    class Test {
    ... // as before


    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jul 31, 2007
    #2
    1. Advertising

  3. First, thank you for your informative tips, I rewrite my code snippet,
    here it is:

    #include <iostream>
    using namespace std;

    template<typename T>
    class Test;

    template<typename T>
    Test<T> index(T start, T end, T step);

    template<typename T>
    class Test {
    public:
    friend Test<T> index(T start, T end, T step);
    };

    template<typename T>
    Test<T> index(T start, T end, T step) {
    cout << "This is index is working\n";
    return Test<T>();
    }

    int main() {

    int start;
    int end;
    int step;

    index(start, end, step);
    }

    It's the same as you think it is supposed to be, no problem with
    compling and linking, but at runtime, a error is raised.
     
    =?gb2312?B?wfXquw==?=, Jul 31, 2007
    #3
  4. Áõê» wrote:
    > First, thank you for your informative tips, I rewrite my code snippet,
    > here it is:
    >
    > #include <iostream>
    > using namespace std;
    >
    > template<typename T>
    > class Test;
    >
    > template<typename T>
    > Test<T> index(T start, T end, T step);
    >
    > template<typename T>
    > class Test {
    > public:
    > friend Test<T> index(T start, T end, T step);
    > };
    >
    > template<typename T>
    > Test<T> index(T start, T end, T step) {
    > cout << "This is index is working\n";
    > return Test<T>();
    > }
    >
    > int main() {
    >
    > int start;
    > int end;
    > int step;
    >
    > index(start, end, step);
    > }
    >
    > It's the same as you think it is supposed to be, no problem with
    > compling and linking, but at runtime, a error is raised.


    What error do *you* get?

    You're passing 'start', 'end', 'step' into the function _without_
    _giving them any value_. The lvalue-to-rvalue conversion required
    for argument passing causes the program to have *undefined behaviour*.

    Try initialising all your variables. Or just call

    index(1, 2, 3);

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jul 31, 2007
    #4
  5. Forget about the runtime error, it's because I used 3 variables before
    I define them, sorry about that, it's OK when I initialize them. But a
    new linkage error show itself when I tried to assign the return value
    of index to another Test<T> object, here is the code snippet:

    #include <iostream>
    using namespace std;

    template<typename T>
    class Test;

    template<typename T>
    Test<T> index(T start, T end, T step) {
    cout << "This is index is working\n";
    return Test<T>();
    }

    template<typename T>
    class Test {
    public:
    friend Test<T> index(T start, T end, T step);

    };


    int main() {

    int start = 1;
    int end = 32;
    int step = 1;

    Test<int> rslt = index(start, end, step);
    }

    The error is:

    Test.obj : error LNK2019: unresolved external symbol "class Test<int>
    __cdecl index(int,int,int)" (?index@@YA?AV?$Test@H@@HHH@Z) referenced
    in function _main
     
    =?gb2312?B?wfXquw==?=, Jul 31, 2007
    #5
  6. should be;


    template<typename T>
    class Test {
    public:
    template<typename T> //look here
    friend Test<T> index(T start, T end, T step);

    };
     
    hurcan solter, Jul 31, 2007
    #6
  7. hurcan solter wrote:
    > should be;
    >
    >
    > template<typename T>
    > class Test {
    > public:
    > template<typename T> //look here
    > friend Test<T> index(T start, T end, T step);
    >
    > };


    You can't redefine 'T' here, I think. If you only wanted to make
    the 'index<T>' a friend (instantiated on the same 'T' as the class
    'Test'), then a pair of angle brackets is in order (I missed that
    in my post:

    template<typename T>
    class Test {
    public:
    friend Test<T> index<>(T start, T end, T step);
    // ^^^^
    };

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jul 31, 2007
    #7

  8. > You can't redefine 'T' here, I think. If you only wanted to make
    > the 'index<T>' a friend (instantiated on the same 'T' as the class
    > 'Test'), then a pair of angle brackets is in order (I missed that
    > in my post:
    >
    > template<typename T>
    > class Test {
    > public:
    > friend Test<T> index<>(T start, T end, T step);
    > // ^^^^
    > };
    >

    yes you can. it's so called friend template, in that case,all
    instantiantions of the
    template is the friend of class Test.Not that it's useful in this case
    though, so yours
    is the probably way to go.
     
    hurcan solter, Jul 31, 2007
    #8
  9. hurcan solter wrote:
    >> You can't redefine 'T' here, I think. If you only wanted to make
    >> the 'index<T>' a friend (instantiated on the same 'T' as the class
    >> 'Test'), then a pair of angle brackets is in order (I missed that
    >> in my post:
    >>
    >> template<typename T>
    >> class Test {
    >> public:
    >> friend Test<T> index<>(T start, T end, T step);
    >> // ^^^^
    >> };
    >>

    > yes you can. it's so called friend template, in that case,all
    > instantiantions of the
    > template is the friend of class Test.Not that it's useful in this case
    > though, so yours
    > is the probably way to go.


    I repeat, the name 'T' shall not be redeclared in the definition of
    'Test' for any other purpose. Try this:

    template<class T> class A {
    A(T) {}
    template<class T> friend void foo(T t);
    // template<class U> friend void foo(U u);
    };

    template<class T> void foo(T t)
    {
    A<A<T> > aat(A<int>(42));
    }

    int main()
    {
    foo(0);
    }

    Then, after it fails, comment the 'foo(T t)' declaration in the
    class template, and uncomment the 'foo(U u)' declaration and try
    again.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Aug 1, 2007
    #9
  10. =?gb2312?B?wfXquw==?=

    Guest Guest

    Hi folks,

    Thanks for your informative tips, both of your answers can solve my
    problem successfully. But I have a question coming into my mind:

    If there is any difference between:

    template<typename T>
    class Test {
    friend Test<T> index<>(T, T, T);
    // ^^^
    };

    and

    class Test {
    friend Test<T> index<T>(T, T, T);
    // ^^^
    };

    I know you've explained it, but how can I prove that they are indeed
    different, thank you.
     
    Guest, Aug 1, 2007
    #10
  11. wrote:
    > Thanks for your informative tips, both of your answers can solve my
    > problem successfully. But I have a question coming into my mind:
    >
    > If there is any difference between:
    >
    > template<typename T>
    > class Test {
    > friend Test<T> index<>(T, T, T);
    > // ^^^
    > };
    >
    > and
    >
    > class Test {
    > friend Test<T> index<T>(T, T, T);
    > // ^^^
    > };
    >
    > I know you've explained it, but how can I prove that they are indeed
    > different, thank you.


    I am not sure they are different, to be honest. The <T> after 'index'
    is actually implied by the empty angle brackets.

    Now, if you were to write

    template<class T>
    class Test {
    template<class U> friend Test<U> index(U,U,U);
    };

    That would definitely be different. It means that _any_ instantiation
    of the 'index' template is a friend of this instantiation of 'Test'.
    The usefulness of that is questionable, but it would allow you to do

    template<class S> Test<S> index(S s1, S s2, S s3)
    {
    Test<blalblah> someOtherTest;
    // and then access 'someOtherTest's privates
    }

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Aug 1, 2007
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. freegnu
    Replies:
    2
    Views:
    343
    freegnu
    Oct 23, 2006
  2. Replies:
    1
    Views:
    1,362
    Jim Langston
    Nov 9, 2006
  3. Replies:
    2
    Views:
    680
    Triple-DES
    Feb 26, 2008
  4. slocum
    Replies:
    4
    Views:
    1,440
    Martin York
    Apr 10, 2008
  5. Rui Maciel
    Replies:
    11
    Views:
    1,106
    Francesco S. Carta
    Jul 13, 2010
Loading...

Share This Page