I was updating a project to use C++17 and found a few instances where code that followed this pattern was causing a compile error on recent versions of clang:
#include <boost/variant.hpp>
struct vis : public boost::static_visitor<void>
{
void operator()(int) const { }
};
int main()
{
boost::variant<int> v = 0;
boost::apply_visitor(vis{}, v);
}
Using clang v8.0 in C++17 mode, this fails with the following error:
<source>:11:30: error: temporary of type 'boost::static_visitor<void>' has protected destructor
boost::apply_visitor(vis{}, v);
^
/opt/compiler-explorer/libs/boost_1_64_0/boost/variant/static_visitor.hpp:53:5: note: declared protected here
~static_visitor() = default;
However, it compiles cleanly in C++14 mode. I found that if I change the brace initialization vis{}
to parentheses vis()
, then it compiles correctly in both modes. Every version of gcc that I've tried allows both variants in C++17 mode.
Is this a correct change in behavior from C++14 to C++17, or is this a clang bug? If it is correct, why is it now invalid in C++17 (or maybe it always was, but clang just allows it in earlier standard revisions)?
clang is correct here. Here's a reduced example:
struct B {
protected:
B() { }
};
struct D : B { };
auto d = D{};
In C++14, D
is not an aggregate because it has a base class, so D{}
is "normal" (non-aggregate) initialization which invokes D
's default constructor, which in turn invokes B
's default constructor. This is fine, because D
has access to B
's default constructor.
In C++17, the definition of aggregate was widened - base classes are now allowed (as long as they're non-virtual
). D
is now an aggregate, which means that D{}
is aggregate initialization. And in aggregate-initialization, this means that we (the caller) are initializing all the subobjects - including the base class subobject. But we do not have access to B
's constructor (it is protected
), so we cannot invoke it, so it is ill-formed.
Fear not, the fix is easy. Use parentheses:
auto d = D();
This goes back to invoking D
's default constructor as before.
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