template friend functions of template class
Asked Answered
D

4

6

I have the following template class and template function which intends to access the class' private data member:

#include <iostream>

template<class T>
class MyVar
{
    int x;
};

template<class T>
void printVar(const MyVar<T>& var)
{
    std::cout << var.x << std::endl;
}

template<class T>
void scanVar(MyVar<T>& var)
{
    std::cin >> var.x;
}

struct Foo {};

int main(void)
{
    MyVar<Foo> a;
    scanVar(a);
    printVar(a);
    return 0;
}

To declare the two functions as MyVar<T>'s friend functions, I've tried the following ways inside the declaration of template<class T> class MyVar to declare friendship. None of them works. How should I do?

template<class T> friend void printVar(const MyVar&);
template<class T> friend void scanVar(MyVar&);
// compilation error

template<class T> friend void printVar(const MyVar<T>&);
template<class T> friend void scanVar(MyVar<T>&);
// compilation error

friend void printVar(const MyVar<T>&);
friend void scanVar(MyVar<T>&);
// link error

friend void printVar(const MyVar&);
friend void scanVar(MyVar&);
// link error too
Darrel answered 25/5, 2015 at 13:43 Comment(5)
Did you try the last one with inline definition? Like thisBreakout
@Breakout It works. Is inlined definition the only way to solve it?Darrel
Well, I checked again and found that your fourth solution seems to work, too... See here - What did you do differently? Note that the implementation of the functions need to be in the header file. Can it be the problem that it is then defined multiple times? What's the linker error? Inlining solves this "multiple definition" linker error, if this is what you got. You can also put the definition outside of the class but add the keyword inline in front of it to solve it.Breakout
@Breakout The errors were indeed undefined reference to scanVar(MyVar<Foo>&)', and adding inline` in front of either the friend declarations or in front of the function definitions didn't work.Darrel
@Breakout You can get the link error by completing main() definition like here.Darrel
N
6

The simplest option is to define the friend within the class:

template<class T>
class MyVar
{
    int x;

    friend void printVar(const MyVar & var) {
        std::cout << var.x << std::endl;
    }
    friend void scanVar(MyVar & var) {
        std::cin >> var.x;
    }
};

The downside is that the functions can only be called through argument-dependent lookup. That's not a problem in your example, but might be a problem if they don't have a suitable argument, or you want to specify the name without calling it.

If you want a separate definition, then the template will have to be declared before the class definition (so it's available for a friend declaration), but defined afterwards (so it can access the class members). The class will also have to be declared before the function. This is a bit messy, so I'll only show one of the two functions:

template <typename T> class MyVar;
template <typename T> void printVar(const MyVar<T> & var);

template<class T>
class MyVar
{
    int x;

    friend void printVar<T>(const MyVar<T> & var);
};

template <typename T> void printVar(const MyVar<T> & var) {
    std::cout << var.x << std::endl;
}
Niagara answered 25/5, 2015 at 13:58 Comment(0)
C
2

I managed to get the following work

#include <iostream>

template<class T>
class MyVar;

template<class T>
void printVar(const MyVar<T>& var);

template<class T>
void scanVar(MyVar<T>& var);

template<class T>
class MyVar
{
    int x;
    friend void printVar<T>(const MyVar<T>& var);
    friend void scanVar<T>(MyVar<T>& var);
};

template<class T>
void printVar(const MyVar<T>& var)
{
    std::cout << var.x << std::endl;
}

template<class T>
void scanVar(MyVar<T>& var)
{
    std::cin >> var.x;
}

struct Foo {};

int main(void)
{
    MyVar<Foo> a;
    scanVar(a);
    printVar(a);
    return 0;
}

UPD: http://en.cppreference.com/w/cpp/language/friend talks about a similar case with operators under "Template friend operators":

A common use case for template friends is declaration of a non-member operator overload that acts on a class template, e.g. operator<<(std::ostream&, const Foo<T>&) for some user-defined Foo<T>

Such operator can be defined in the class body, which has the effect of generating a separate non-template operator<< for each T and makes that non-template operator<< a friend of its Foo<T>

...

or the function template has to be declared as a template before the class body, in which case the friend declaration within Foo<T> can refer to the full specialization of operator<< for its T

Corpora answered 25/5, 2015 at 13:53 Comment(0)
P
1

This one compiles on MSVC2013. Basicly adds the forward declarations to class and functions before the friend

template<class T>   class MyVar ; // class forward declaration

template<class T> ; // function forward declarations
void printVar(const MyVar<T>& var);
template<class T>
void scanVar(MyVar<T>& var);

template<class T>
class MyVar
{
    friend void printVar<T>(const MyVar<T>&);
    friend void scanVar<T>(MyVar<T>&);
    int x;
};

template<class T>
void printVar(const MyVar<T>& var)
{
    std::cout << var.x << std::endl;
}

template<class T>
void scanVar(MyVar<T>& var)
{
    std::cin >> var.x;
}

struct Foo {};

int main1(void)
{
    MyVar<Foo> a;
    scanVar(a);
    printVar(a);
    return 0;
}
Pretension answered 25/5, 2015 at 13:55 Comment(0)
A
1

Well there is a solution that is both simple and involving separation between declaration & definition of the friend function. In the declaration of the friend function (inside the class) you have to give a different template param from the one the class accepts (and it make sense cause this function is not a member of this class).

template<class T>
class MyVar
{
    int x;

    template<typename Type>
    friend void printVar(const MyVar<Type> & var);

    template<typename Type>
    friend void scanVar(MyVar<Type> & var);
};

template<typename T>
void printVar(const MyVar<T> & var) {

}

template<typename T>
void scanVar(MyVar<T> & var) {

}

No forward declaration needed, as well as there is a separation of declaration & definition.

Atlantes answered 10/7, 2020 at 12:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.