问题
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?
回答1:
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
.
来源:https://stackoverflow.com/questions/31510844/is-there-a-way-to-specify-all-classes-in-a-variadic-parameter-pack-to-be-friend