Home > Software engineering >  How do I make C friend template specializations work?
How do I make C friend template specializations work?

Time:04-05

I have a class that overloads the bit shift operator like the following:

    template<typename DataType>
    friend Packet& operator << (Packet& pkt, const DataType& data)
    {
          std::cout << "this compiles" << std::endl;
    }

but when I try to make a specialization of it like this :

    template<typename DataType>
    friend Packet& operator << (Packet& pkt, const DataType& data)
    {
          std::cout << "this doesn't compile" << std::endl;
    }

    template<>
    friend Packet& operator<<<std::string> (Packet& pkt, const std::string& data)
    {
          std::cout << "this doesn't compile" << std::endl;
    }

it throws a compile time error:

Error   C2116   'operator <<': function parameter lists do not match between declarations 

what I'm I doing wrong here ?

CodePudding user response:

If I get you correctly, following is what you want to achieve right?

 
#include <iostream>
class Packet
{
    public:
    template<class T>
    friend Packet& operator << (Packet& pkt, const T& data);
};

template<class DataType>
Packet& operator << (Packet& pkt, const DataType& data)
{
std::cout << "primary" << std::endl;
return pkt; // handle it as as per your logic
}

template<>
Packet& operator<< (Packet& pkt, const std::string& data)
{
        std::cout << "specialisation for std::string" << std::endl;
        return pkt; // handle it as as per your logic
}

int main()
{
    
    Packet p1;
    p1<<4;
    p1<<std::string("samplestring");
    return 0;
}

CodePudding user response:

How do I make C friend template specializations work?

A friend template can declare only primary templates and members of primary templates. Any partial specializations and explicit specializations associated with a primary template are automatically considered friends too.

So to solve the problem in your code, you can add a friend template declaration for the primary template inside class Packet and then define that primary template as well as any other specialization outside the class as shown below:

#include <iostream>
#include<string>

struct Packet
{
    //friend template declaration for primary template 
    template<typename DataType>
    friend Packet& operator << (Packet& pkt, const DataType& data);
};

//implementation of primary template
template<typename DataType>
Packet& operator << (Packet& pkt, const DataType& data)
{
      std::cout << "primary template called" << std::endl;
      return pkt;
}
//implementation of explicit specialization
template<>
Packet& operator<<<std::string> (Packet& pkt, const std::string& data)
{
      std::cout << "specialization for std::string called" << std::endl;
      return pkt;
}
int main()
{
    Packet p;
    p << 100; //uses primary template
    
    std::string s("someString");
    p << s; //uses specialization for std::string
    return 0;
}

Working demo.

The changes that i made include:

  1. Added a friend template declaration for the primary template inside Packet.
  2. Added implementation for both the primary template as well as explicit specialization outside the class Packet. Note that there is no need for the friend keyword in the implementation outside class. Moroever, the explicit specialization is automatically a friend of Packet so no need to have a friend declaration for this specialization inside the class Packet.
  3. Added return statement that were missing in the original example question.
  • Related