Consider the code bellow:
#include <type_traits>
#include <iostream>
struct B {
virtual const char* whoami() const { return "I am a B!\n"; };
};
struct D : B {
const char* whoami() const override { return "I am a D!\n"; };
};
void foo_impl( B*(*pf)() )
{
B* b = pf();
std::cout << b->whoami();
}
template <class C>
auto foo( C*(*pf)() ) -> std::enable_if_t<std::is_base_of<B, C>::value> {
foo_impl(reinterpret_cast<B*(*)()>(pf));
}
D *bar() {
static D d_; // kludge to work around dangling pointer problem.
// Unrelated to the actual question
return &d_;
}
int main() {
foo(bar); // prints "I am a D!" on gcc 5.1
return 0;
}
Function pointers of course cannot be coerced according to the standard, and maybe there is no need (we can always just return a B*
), but please humor me. As far as I can tell, there is no possible violation of the LSP, so if it was possible, a function returning D*
could be used in place of a function returning B*
in a completely opaque manner.
The thin foo
template preforms the static type checking I wish the compiler would do, and then throws the type information to the wind. At this point, I'm aware that unless I cast back to the original pointer type, the behavior is undefined (C++11 ยง5.2.10/6).
My question is therefore:
Is there a practical reason, unrelated to the standard, that can cause the above code to fail? Or is there another standard reference, which can assuage the unpleasantness of the UB in the above code?
The following statement of your post is not correct :
This is not true, because converting
D*
toB*
is not just a cast : a shift in the address may be required. It does not in your example because you do not use multiple inheritance.Consider this example:
This prints
I am A
, even though you thought you used aB
. The function called is effectivelyB::whomai
, but the data member underneath is the one fromA
, since the address has not been shifted as it would have been with a properstatic_cast
of the pointer.