[MPL] HAS_XXX gives the wrong answer after "enable_if" on incomplete type in GCC 4.6/7

I've run into an unexpected behaviour, and I'm not sure if the
compiler has a bug, if Boost.MPL has a bug, or if I have the wrong
expectations. I am using Boost v1.49.0, but I also tested r82084 of
the Boost trunk.
In particular, I have:
BOOST_MPL_HAS_XXX_TRAIT_DEF(trait)
// skipping important code here
struct traitor_1 { typedef void *trait; };
struct traitor_2 { typedef void *trait; };
static_assert(has_trait

I've run into an unexpected behaviour, and I'm not sure if the compiler has a bug, if Boost.MPL has a bug, or if I have the wrong expectations. I am using Boost v1.49.0, but I also tested r82084 of the Boost trunk.
I'm not sure which is the case either, but notice that a simple
workaround is to define f after traitor_1 is complete (you can still
*declare* f where you do now). This is not an unreasonable
requirement, because the body of f performs a traitor_1 -> C
conversion, for which it needs to instantiate the constructor of C,
for which it needs to instantiate has_traitor

On 18/12/2012, Nathan Ridge
I'm not sure which is the case either, but notice that a simple workaround is to define f after traitor_1 is complete (you can still *declare* f where you do now).
Yes, you are correct; my actual code is a fair bit more complicated,
but there is definitely a workaround.
Moreover, to change this to a compile-time error, I'll change the
definition of "traitor_1" to include a static assertion as follows.
struct traitor_1
{
typedef void *trait;
static_assert(has_trait

Duncan Exon Smith wrote:
Nathan Ridge wrote:
I'm not sure which is the case either, but notice that a simple workaround is to define f after traitor_1 is complete (you can still *declare* f where you do now).
Yes, you are correct; my actual code is a fair bit more complicated, but there is definitely a workaround.
Moreover, to change this to a compile-time error, I'll change the definition of "traitor_1" to include a static assertion as follows.
struct traitor_1 { typedef void *trait; static_assert(has_trait
::value, "traitor_1::trait missing"); }; Without a static assertion failing, real code would compile with the wrong value for "has_trait<>". I think adding this to the definition will fix most of the otherwise "silent" bugs.
I'm still interested in whether this is a defect, or just a limitation of C++, if anyone has an opinion...
For what it's worth, I was surprised that has_trait didn't error out when passed an incomplete type. It seems like just having it return false with incomplete types would be problematic for more than just the incorrect deduction -- it could lead to ODR violations, etc. Perhaps the macros should have a sizeof(T) line added. . . Thanks, Nate

Nathan Crookston wrote:
Duncan Exon Smith wrote:
I'm still interested in whether this is a defect, or just a limitation
of C++, if anyone has an opinion...
For what it's worth, I was surprised that has_trait didn't error out when passed an incomplete type. It seems like just having it return false with incomplete types would be problematic for more than just the incorrect deduction -- it could lead to ODR violations, etc.
Perhaps the macros should have a sizeof(T) line added. . .
Looking at the implementation, it appears that the decision to return false in the event of incomplete types is intentional. I found that surprising -- the documentation doesn't mention that, from what I see. Nate
participants (3)
-
Duncan Exon Smith
-
Nathan Crookston
-
Nathan Ridge