Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unconventional uses of friend in c++

I know the general use cases for the friend keyword with regards to encapsulation but one a couple of occasions, I have needed the friend keyword just to "get the job done". These use cases don't make me happy so I'm wondering if there are some alternatives. Here's the first minimal example:

struct Foo{
  enum class Bar{
    a=1,b=2,c=4
  };

  // need to tell the compiler of operator| before it gets used
  // but it can't be a member function of Foo: so add friend keyword  
  friend Bar operator|(const Bar& b1, const Bar& b2);  

  // constructor needs a default value using 
  // operator| for Bars 
  Foo( Bar b = Bar::a | Bar::b );
};

// definition of operator|, etc.

Is there any way for the compiler to see the declaration of the operator| for the nested class, inside of interface, before the default values are given at the Foo constructor declaration?

I also sometimes find myself using the friend keyword in defining symmetric operations of nested classes within templates. For example:

template<typename T>
struct A{
  struct B{
    friend bool operator==(const B& x, const B& y) { return true; }  
  };  
};

The operator== does not require friendship from an encapsulation perspective. But due to operator== not actually being a templated function and the compiler being unable to deduce the types of nested classes within templates, this seems to be the only reasonable "trick" to keep operator== as a free function.

As I said, these choices do work, but I'm wondering if there are better choices/practices out there.

like image 833
user137364 Avatar asked Dec 20 '21 06:12

user137364


People also ask

What is the use of friend function?

A friend function is a function that isn't a member of a class but has access to the class's private and protected members.

What is the purpose of friend function and friend classes explain with the help of suitable example?

Friend Class A friend class can access private and protected members of other class in which it is declared as friend. It is sometimes useful to allow a particular class to access private members of other class. For example, a LinkedList class may be allowed to access private members of Node.

What is the main reason for creating a friend class?

A friend class is a class that can access the private and protected members of a class in which it is declared as friend. This is needed when we want to allow a particular class to access the private and protected members of a class.


1 Answers

In fact, I would say it's perfectly conventional. While, as mentioned by Evg, hidden friends have special benefits, visible friends are also great to have!

To make this more of an answer, consider for example libstdc++'s implementation of std::unreachable_sentinel_t. This can be returned as the end() of an unbounded "generator range", such as a std::ranges::iota_view{0}. It's very similar to your second example:

struct unreachable_sentinel_t
{
    template<weakly_incrementable _It>
    friend constexpr bool
    operator==(unreachable_sentinel_t, const _It&) noexcept
    { return false; }
};

inline constexpr unreachable_sentinel_t unreachable_sentinel{};

Regular iterators and sentinels are defined as nested classes and also rely on friendship, though their comparison operators typically do need the privileged access. However, even if you could provide an out-of-line definition, an additional benefit of inlining friends in templates is that you don't have to repeat the exact template header, including potentially complicated constraints.

If it helps, in C++ you can think of free functions like these, whether or not they are friends, as being part of the public interface of the classes of their arguments, due to argument-dependent lookup. As such, even if you don't technically need the privilege of friendship, granting it does not break encapsulation.

As long as you're aware of the nuance of hidden friendship, just use friend if it gets the job done!

like image 142
sigma Avatar answered Oct 13 '22 04:10

sigma