I try next code with three compilers (msvc2017, gcc8.2, clang7.0) and msvc2017 works all the way, but gcc and clang not. I want to understand what is wrong with my code, and why compiler can't compile it.
#include <cassert>
#include <iostream>
#include <cstdlib>
class Downloader
{
public:
struct Hints
{
int32_t numOfMaxEasyHandles = 8;
//Hints(){} // <= if I uncomment this all works gcc+clang+msvc
//Hints() = default; // <= if I uncomment this neither clang no gcc works (msvc - works)
};
static Downloader *Create(const Hints &hints = Hints());
};
Downloader* Downloader::Create(const Hints &hints)
{
std::cout << hints.numOfMaxEasyHandles << std::endl;
return nullptr;
}
int main()
{
return 0;
}
You can play with this code yourself on https://wandbox.org/ and see error:
prog.cc:16:58: error: default member initializer for 'Downloader::Hints::numOfMaxEasyHandles' required before the end of its enclosing class
static Downloader *Create(const Hints &hints = Hints());
^
prog.cc:11:37: note: defined here
int32_t numOfMaxEasyHandles = 8;
^~~~
Why gcc and clang not compile this code even with uncomment Hints() = default
?
My compile commands:
$ g++ prog.cc -std=gnu++2a
$ clang++ prog.cc -std=gnu++2a
But if I uncomment Hints(){}
all three compilers works. Maybe it is compiler bug? Thanks in advance.
This is a clang and gcc bug, we have a clang bug report for this: default member initializer for 'm' needed within definition of enclosing class for default argument of function which has the following example:
#include <limits>
class A
{
public:
class B
{
public:
explicit B() = default;
~B() = default;
private:
double m = std::numeric_limits<double>::max();
};
void f(double d, const B &b = B{}) {}
};
int main()
{
A a{};
a.f(0.);
}
which produces the following similar diagnostic:
t.cpp(15,34): error: default member initializer for 'm' needed within definition of enclosing class 'A' outside of member functions
void f(double d, const B &b = B{}) {}
^
t.cpp(12,20): note: default member initializer declared here
double m = std::numeric_limits<double>::max();
^
Richard Smith indicates this is a bug:
Regarding comment#0: if we want to fix this once-and-for-all, we should use the same technique we use for delayed template parsing: teach Sema to call back into the parser to parse the delayed regions on-demand. Then we would only reject the cases where there's an actual dependency cycle.
Although does not explain why in details.
As of 2021 it's still not fixed, but as a work-around I'm using something like this:
namespace detail {
struct DownloaderHints
{
int32_t numOfMaxEasyHandles = 8;
};
}
class Downloader {
public:
using Hints = details::DownloaderHints;
static Downloader *Create(const Hints &hints = Hints());
};
As of 2022 the bug is still not fixed, but yet another workaround is to default a constructor in the .cpp file:
class Downloader
{
public:
struct Hints
{
int32_t numOfMaxEasyHandles = 8;
Hints();
};
static Downloader *Create(const Hints &hints = Hints());
};
// In .cpp:
Downloader::Hints::Hints() = default;
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