Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class template befriending function template

Tags:

c++

templates

I get a linker error when I try to create an executable from the following code. I get the impression I need to place a few "typenames" around or make some forward declarations; I've tried a few combinations but none worked.

template<typename T>
class enabled
{
  private:
    T type_;
    friend const T& typeof(const enabled<T>& obj); // Offending line
};

template<typename T>
const T& typeof(const enabled<T>& obj) {
    return obj.type_;
}


int main()
{
    enabled<std::string> en;
    std::cout << typeof(en);

    std::cin.clear(), std::cin.get();
    return 0;
}

1>main.obj : error LNK2001: unresolved external symbol "class std::string const& __cdecl typeof(class enabled<class std::string> const&)"

like image 576
Paul Manta Avatar asked Oct 29 '11 18:10

Paul Manta


2 Answers

By forward declaring and specifying that the function is templated

template<typename T> class enabled;

template<typename T>
const T& typeof(const enabled<T>& obj) {
    return obj.type_;
}

template<typename T>
class enabled
{
  private:
    T type_;
    friend const T& typeof<>(const enabled<T>& obj);
};
like image 123
JRL Avatar answered Sep 29 '22 15:09

JRL


The problem is that the function which is a friend of the class, is not a function template, while the function you actually have defined is a function template.

All that you need to do is make the friend a function template as:

template<typename T>
class enabled
{
  private:
    T type_;

    template<typename U> //<-------------------------------note this
    friend const U& typeof_(const enabled<U>& obj);  //use U 
};

Now this compiles just fine : http://www.ideone.com/VJnck

But it makes all instantiations of typeof_<U> friend of all instantiations of enabled<T>, which means typeof_<int> is a friend of enabled<T> for all possible value of T, and vice versa.

So a better solution is to make the function non-template and define it inside the class as:

template<typename T>
class enabled
{
  private:
    T type_;

    friend const T& typeof_(const enabled<T>& obj)
    {
        return obj.type_;
    }
};

Demo : http://www.ideone.com/Rd7Yk

Note that I replaced typeof with typeof_, as GCC has an extension with name typeof, and so it was giving error on ideone (as I can't turnoff extensions).

like image 30
Nawaz Avatar answered Sep 29 '22 16:09

Nawaz