The following code…
// main.cpp
#include <grpcpp/grpcpp.h>
class ClientContextContainer {
public:
ClientContextContainer( int i ) : i_(i) {}
private:
grpc::ClientContext client_context_;
int i_;
};
class ArrayContainer {
public:
ArrayContainer() : ccc_{ {42}, {1138} } {}
private:
ClientContextContainer ccc_[2];
};
int main( int argc, char* argv[] ) {
ArrayContainer ac;
return 0;
}
…generates this error:
root@178258c7c52d:/tmp# /usr/bin/x86_64-linux-gnu-g++ --version && /usr/bin/x86_64-linux-gnu-g++ -c ./main.cpp
x86_64-linux-gnu-g++ (Debian 8.3.0-6) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
./main.cpp: In constructor 'ArrayContainer::ArrayContainer()':
./main.cpp:15:41: error: use of deleted function 'ClientContextContainer::ClientContextContainer(ClientContextContainer&&)'
ArrayContainer() : ccc_{ {42}, {1138} } {}
^
./main.cpp:4:7: note: 'ClientContextContainer::ClientContextContainer(ClientContextContainer&&)' is implicitly deleted because the default definition would be ill-formed:
class ClientContextContainer {
^~~~~~~~~~~~~~~~~~~~~~
./main.cpp:4:7: error: 'grpc::ClientContext::ClientContext(const grpc::ClientContext&)' is private within this context
In file included from /usr/local/include/grpcpp/client_context.h:37,
from /usr/local/include/grpcpp/grpcpp.h:53,
from ./main.cpp:2:
/usr/local/include/grpcpp/impl/codegen/client_context.h:388:3: note: declared private here
ClientContext(const ClientContext&);
^~~~~~~~~~~~~
I do not fully understand the compiler error, but by my reading, it implies that the problem is that class ClientContextContainer
‘s move constructor is implicitly deleted because the class’ member grpc::ClientContext
object has a private copy constructor. (Inspection of client_context.h
shows that its assignment operator is also private).
Fine. But if that’s the case, why can’t I reproduce the compile error if I replace the grpc::ClientContext
member object with my own object that also has a private copy constructor (and assignment operator)?
// main.cpp
//#include <grpcpp/grpcpp.h>
class FauxClientContext {
public:
FauxClientContext() {}
private:
FauxClientContext( const FauxClientContext& );
FauxClientContext& operator=( const FauxClientContext& );
};
class ClientContextContainer {
public:
ClientContextContainer( int i ) : i_(i) {}
private:
FauxClientContext client_context_;
//grpc::ClientContext client_context_;
int i_;
};
class ArrayContainer {
public:
ArrayContainer() : ccc_{ {42}, {1138} } {}
private:
ClientContextContainer ccc_[2];
};
int main( int argc, char* argv[] ) {
ArrayContainer ac;
return 0;
}
root@178258c7c52d:/tmp# /usr/bin/x86_64-linux-gnu-g++ --version && /usr/bin/x86_64-linux-gnu-g++ -c ./main.cpp
x86_64-linux-gnu-g++ (Debian 8.3.0-6) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
root@178258c7c52d:/tmp#
What’s the true nature of the error compiling the first version of main.cpp
? That I could successfully compile the second version of main.cpp
implies that it’s not what I interpreted the compiler error message to mean.
To those familiar with grpc
, the root of this line of inquiry is: is it possible to construct an array of objects, in an initializer-list, if the objects have a member grpc::ClientContext
object?
2
Answers
My original post contained too much speculation and further analysis of your issue, the first update of my answer contained a misassumption about the actual underlying issues here further on unfortunately. So this answer should be the final version and addresses all relevant issues here hopefully.
When are move constructors implicitly deleted:
Excerpt from https://en.cppreference.com/w/cpp/language/move_constructor
Why you get a compile error:
According to the standard at least already since C++11, you shouldn’t actually since you use the C++11 direct list initialization syntax (see your array) with a well defined constructor for your case correctly. Copy and move constructors are not required here for your case at least. g++ has a still not fixed bug (almost historical now) that causes your problems here, see
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63707
Your compiler works standard conformably (as far as I was able to test it) at least as long as your class ClientContextContainer doesn’t hold a member whose according class destructor isn’t implicitly (default) defined. That’s not the case for grpc::ClientContext since it has several members (shared pointers) with non-default destructors. That’s why, your modified code snippet with this simple class works well even for the case where all copy/move constructors are private/deleted. Try to introduce a critical member here in terms of the destructor and you’ll be able to reproduce the compile error quickly.
Side note:
Your actual issue here has nothing to do with guaranteed copy elision – introduced in C++17 (that was my misassumption here actually). Maybe it has an indirect relevance here with focus on this g++ bug since if the bug is a missing direct initialization but an illegal underlying usage of copy-initialization, g++ also would violate the guaranteed copy elision requirement of the standard since C++17 here for your case I think.
For further information, see
https://en.cppreference.com/w/cpp/language/direct_initialization
https://en.cppreference.com/w/cpp/language/list_initialization
https://en.cppreference.com/w/cpp/language/copy_initialization
https://en.cppreference.com/w/cpp/language/copy_elision
tl;dr: It’s a compiler bug.
This is a bug in the GCC compiler:
Brace initialization of array sometimes fails if no copy constructor (gcc.gnu.org/bugzilla)
It has been fixed, as of the time of writing, for GCC 11.0, 10.3 and 9.4, but manifests in currently released versions upto and including 10.2.
A reduced testcase due to Jonathan Wakeley:
This works with clang, fails with GCC (see it on GodBolt).