Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to specify all classes in a variadic parameter pack to be friend of the template in order to use operator=?

I have seen a CRTP solution, which extracted the interface into the base class, and friended only one of the pack arguments per base class. Then the most derived class inherited all the friended base classes and implemented the interface.

I cannot use this approach, since I need to protect the assignment operator, which is not inherited.

Also, since the assignment operator has a defined signature with exactly one parameter, I cannot use a key pattern.

This is what I would like to have:

template <typename... F>
struct A {
protected:
    A& operator=(const SomeClass &other) {
        //...
    }
private:
    //I would like to do the following, but it does not work
    friend F...;
}

Is there a way to do what I am needing?

like image 738
LoPiTaL Avatar asked Jul 20 '15 07:07

LoPiTaL


1 Answers

Well, you can always play dirty. First, define a repetition macro:

#define REPEAT_2(M, N) M(N) M(N+1)
#define REPEAT_4(M, N)   REPEAT_2  (M, N) REPEAT_2(M, N+2)
#define REPEAT_8(M, N)   REPEAT_4  (M, N) REPEAT_4(M, N+4)
#define REPEAT_16(M, N)  REPEAT_8  (M, N) REPEAT_8(M, N+8)
#define REPEAT_32(M, N)  REPEAT_16 (M, N) REPEAT_16(M, N+16)
#define REPEAT_64(M, N)  REPEAT_32 (M, N) REPEAT_32(M, N+32)
#define REPEAT_128(M, N) REPEAT_64 (M, N) REPEAT_64(M, N+64)

Then place 128 friend declarations into a variadic class template of your choice:

template <typename... T>
class A
{
    #define FRIEND(N) friend std::tuple_element_t<
                       std::min((std::size_t)N+1, sizeof...(T)), std::tuple<void, T...>>;
    REPEAT_128(FRIEND, 0)

    static constexpr int i = 3;
};

struct X; struct Y; struct Z;
using ASpec = A<X, Y, Z>;
struct X {int i = ASpec::i;};
struct Y {int i = ASpec::i;};
struct Z {int i = ASpec::i;};

template class A<>; // Small test for empty pack

Demo. Credit to @dyp.

If you have access to Boost.Preprocessor, the entire thing can be written far more concisely using BOOST_PP_REPEAT.

like image 191
Columbo Avatar answered Sep 22 '22 17:09

Columbo