1

Was originally working on a question someone else asked earlier: Why string is not printed?C++. Seeing that OP was not quite utilizing the template for DataOut and GetData, so I was trying to make them template as well.

Here's the code I end up having:

#include <iostream>
#include <string>

template<class T>
class Array{
public:
    T U[10];

    friend void DataOut(const Array&);
    friend void GetData(Array&);
};

template<class T>
void DataOut(const Array<T>& arr){
    std::cout << arr.U[0];
}

template<class T>
void Getdata(Array<T>& arr){
    std::cin >> arr.U[0];
    std::cin.clear();
}

int main(){
    Array<std::string> Arr1;
    Getdata(Arr1);
    DataOut(Arr1);
}

However, I got undefined reference for DataOut: main.cpp:(.text+0x3a): undefined reference to 'DataOut(Array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&)'

I found two ways to get around this:

  1. Define the DataOut inside the Array class.
  2. Call DataOut<std::String> in main, instead of just DataOut.

The question is, how come no errors happens to GetData? I also tried to call and define them in different orders, but still the same result.

Is there something I'm missing? Or it's my compiler's (clang 7.0.0) fault?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Ranoiaetep
  • 5,872
  • 1
  • 14
  • 39

2 Answers2

2

You declared two (families of) non-template friend functions

template<class T>
class Array{
public:
    T U[10];

    friend void DataOut(const Array&);
    friend void GetData(Array&);
};

If you want that such a non-template function would be a friend function for a specialization of the class template you have to define it explicitly for that specialization.

Here is a demonstrative program.

#include <iostream>
#include <iomanip>
#include <string>

template <typename T>
class A
{
private:
    T x = T();
    
    friend void f( const A & );
};

void f( const A<int> &a )
{
    std::cout << "a.x = " << a.x << '\n';
}

void f( const A<std::string> &a )
{
    std::cout << std::boolalpha << "a.x is empty = " << a.x.empty() << '\n';
}

int main() 
{
    f( A<int>() );
    f( A<std::string>() );
    
    return 0;
}

Its output is

a.x = 0
a.x is empty = true

If for example you will add the following statement in main

f( A<long>() );

then the compiler will issue an error because there is no such a non-template function. Such function for this specialization of the class template is not defined.

You could define the friend non-template function within the class. In this case the so-called templated entity will be instantiated for each specialization of the class template by the compiler.

That is this function template declaration

template<class T>
void DataOut(const Array<T>& arr){
    std::cout << arr.U[0];
}

has nothing common with the non-template friend function DataOut.

As for this question

The question is, how come no errors happens to GetData? I also tried to call and define them in different orders, but still the same result.

Then you have a typo in naming the function in the class and outside the class. That is you have two different functions GetData and Getdata.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • @Ranoiaetep Do you see that GetData and getData are two different names? That is you made a typo and declared two functions with different names. – Vlad from Moscow May 14 '21 at 21:54
0

Vlad answer most of my question. Meanwhile I figured how to define the friend function as template functions from some gcc warnings:

template<class T>
class Array;         // Forward declaration of the Array<T> class

template<class T>
void DataOut(const Array<T>& arr){
    std::cout << arr.U[0];
}

template<class T>
class Array{
public:
    T U[10];

    friend void DataOut<>(const Array<T>&);    // `<>` used right after `DataOut`
}
Ranoiaetep
  • 5,872
  • 1
  • 14
  • 39