I like it but is access restriction really a problem? In my years of C++ programming it always seemed to be a theoretical problem more than something that leads to crashes.
C++ Patterns: The Badge
21–30 of 160 posts
Re: C++ Patterns: The Badge
#22 template
Badge FakeBadge() {
struct Stub {}
return reinterpret_cast>(Stub());
}Re: C++ Patterns: The Badge
#23I do C++ for almost 20 years but never came across this simple technique before, so I'm quite surprised that I actually like it. I usually avoid 'friend' in these situations and just write //private: before the method declaration. But it actually happened that co-workers used these private methods because they use code-completion instead of reading the header... But I might would call the class Friend or something.
A nice feature I've noticed in Elixir is that giving a function a "@doc false" annotation will actually prevent IDE/REPL autocomplete from completing the function. (It's still there to call if you type it yourself.) Maybe that's something C++ tooling could copy.
Re: C++ Patterns: The Badge
#24I like it but is access restriction really a problem? In my years of C++ programming it always seemed to be a theoretical problem more than something that leads to crashes.
This solves a chronic architectural maintenance problem in complex C++ code bases, which I've also run into countless times. Any visible interface, public or private (via friend), will eventually be used by other programmers for other than its intended use case simply because it is there and accessible. For the maintainer of an interface with a single intended purpose, what should be a clean, tidy modification within…
> With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody.
Re: C++ Patterns: The Badge
#25I like it! The self-documentation of where the call is coming-from is quite nice (though a more descriptive name like CallFrom would make that even clearer, were it the principle intent). I can't help myself, though: template Badge FakeBadge() { struct Stub {} return reinterpret_cast >(Stub()); }
template
class Badge {
friend T;
Badge() {}
};
template
Badge FakeBadge() {
struct Stub {};
return reinterpret_cast>(Stub());
};
class Device {
public:
static Badge getBadge() { return Badge(); }
};
void needDeviceBadge(Badge badge)
{
}
int main()
{
needDeviceBadge(Device::getBadge()); // no error
needDeviceBadge(FakeBadge()); // error!
return 0;
}
g++ errors: badge.cc: In instantiation of ‘Badge 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’
return reinterpret_cast>(Stub());
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A reinterpret_cast won't turn an instance of the Stub local class into a Badge.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.
Re: C++ Patterns: The Badge
#26I like it but is access restriction really a problem? In my years of C++ programming it always seemed to be a theoretical problem more than something that leads to crashes.
This solves a chronic architectural maintenance problem in complex C++ code bases, which I've also run into countless times. Any visible interface, public or private (via friend), will eventually be used by other programmers for other than its intended use case simply because it is there and accessible. For the maintainer of an interface with a single intended purpose, what should be a clean, tidy modification within…
It's also zero width, so no temporaries, etc.
Re: C++ Patterns: The Badge
#27I like it! The self-documentation of where the call is coming-from is quite nice (though a more descriptive name like CallFrom would make that even clearer, were it the principle intent). I can't help myself, though: template Badge FakeBadge() { struct Stub {} return reinterpret_cast >(Stub()); }
Re: C++ Patterns: The Badge
#28Re: C++ Patterns: The Badge
#29Re: C++ Patterns: The Badge
#30Could you make the badge the last argument and give it a default value, so you don't need the initialization at the function call? It looks a bit strange and would need an explanation for why the empty initialization list is there IMO. I'm not sure if it would work, cppreference has this to say about default arguments: > The names used in the default arguments are looked up, checked for accessibility, and bound at th…