template<typename T>
class Badge {
friend T;
Badge() {}
};
template<typename T>
Badge<T> FakeBadge() {
struct Stub {};
return reinterpret_cast<Badge<T>>(Stub());
};
class Device {
public:
static Badge<Device> getBadge() { return Badge<Device>(); }
};
void needDeviceBadge(Badge<Device> badge)
{
}
int main()
{
needDeviceBadge(Device::getBadge()); // no error
needDeviceBadge(FakeBadge<Device>()); // error!
return 0;
}
g++ errors: badge.cc: In instantiation of ‘Badge<T> FakeBadge() [with T = Device]’:
badge.cc:25:38: required from here
badge.cc:10:10: error: invalid cast from type ‘FakeBadge() [with T = Device]::Stub’ to type ‘Badge<Device>’
return reinterpret_cast<Badge<T>>(Stub());
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A reinterpret_cast won't turn an instance of the Stub local class into a Badge<Device>.That doesn't even have to do with friendship/protection. If we move that line into the Device class, the reinterpret_cast still doesn't compile.
The rule should be that if the default constructor of T is not accessible in the scope, then any cast to T * or T & requires a diagnostic. Or something like that.
If I can allocate a suitably aligned buffer of sizeof (T) zeros, and then treat that as a T, I've effectively constructed a T.
It would be better to do eg "return Device::private:get_badge()", but C++ defectively doesn't support that.
Edit: Actually, from reading some of the other comments in the thread, the standard apparently specifies that empty structs are 1 byte in size, so technically they would both be the same size, so casting between them should be fine.
template<typename T>
Badge<T> FakeBadge() {
static struct Stub {} stub;
return *(Badge<T>*)&stub;
};