I have the following code, and I do not understand why the last !has_size<Bar>::value
evaluates to true only if I don't comment out the exact same static_assert( !has_size<Bar>::value, ...)
prior to defining Bar
#include <type_traits>
template <class, class = void> struct has_size : std::false_type {};
template <class T> struct has_size<
T, typename std::enable_if<(sizeof(T) > 0)>::type>
: std::true_type
{};
// expected success
struct Foo {};
static_assert( has_size<Foo>::value, "Foo doesn't have size");
struct Bar; // declare bar
// if we comment out this line, the static_assert below struct Bar{} fails
static_assert( !has_size<Bar>::value, "Bar has a size");
struct Bar {}; // define bar
// why is this true now, but false if I comment out the previous assertion?
static_assert( !has_size<Bar>::value, "Bar has a size");
I want to make some templating decisions later based on the value of has_size<Bar>
. The behavior is the same across msvc, gcc, and clang. I'm trying to figure out if this is intended and well-documented behavior, or if I'm wandering into UB land or some other calamity by relying on this behavior. Thoughts?
You can think of class template instantiations as being "cached" or "memoized." More formally, class templates have a single point of instantiation per translation unit.
So when you write:
struct Bar;
static_assert( !has_size<Bar>::value, "Bar has a size"); // #1
struct Bar {};
static_assert( !has_size<Bar>::value, "Bar has a size"); // #2
has_size<Bar>
is instantiated at #1
. That is its only point of instantiation. At #2
, we don't "redo" that calculation - so it is still false. If we did this again from a different translation unit, in a way that would give a different answer, that would be ill-formed (no diagnostic required), but in this situation - this is a well-formed program.
When you comment out #1
, now the point of instantiation of has_size<Bar>
becomes #2
. And at that point in the program, Bar
is complete, so has_size<Bar>
is now true_type
... so the static assertion triggers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With