I need to check if a class C
has a default constructor, either implicit or custom, and either public
, protected
or private
.
I tried using std::is_default_constructible<C>::value
, which returns true if C
has a public
default constructor (either implicit or custom) but false
if C
has a protected
or private
default constructor (seams to be the standard behavior though.)
Is there any way to check if a class has a protected
or private
default constructor ?
Note (if this may help): the check is performed from a function that is friend
of the class C
to be checked.
I need to perform this check in order to default-construct objects corresponding to the nullptr
pointers of the m_objs
tuple, member of a Foo
object (partial Foo definition below):
template<class... Objects>
class Foo
{
public:
Foo(Objects*... objects)
: m_objs(objects...)
{
// User construct a Foo objects passing a pack of pointers
// some of them are nullptr, some are not.
// The following call should default-construct objects corresponding
// to the null pointers of m_objs member tuple:
objs_ctor<Objects...>();
}
private:
template<class Obj, class O1, class ...On>
void objs_ctor()
{
objs_ctor<Obj>(); objs_ctor<O1, On...>();
}
template<class Obj>
typename std::enable_if<std::is_default_constructible<Obj>::value, void>::type
objs_ctor()
{
Obj*& obj = std::get<Obj*>(m_objs);
if (obj == nullptr)
obj = new Obj; // default-construct Obj
}
template<class Obj>
typename std::enable_if<!std::is_default_constructible<Obj>::value, void>::type
objs_ctor()
{
Obj*& obj = std::get<Obj*>(m_objs);
assert(obj != nullptr); // terminate if not pre-constructed
}
private:
std::tuple<Objects*...> m_objs;
};
which is intended to be used as:
struct A { };
class B {
B() = default;
template <class... Ts>
friend class Foo;
};
int main() {
// currently asserts, even though Foo<A,B> is a friend of B
// and B is default-constructible to its friends
Foo<A, B> foo(nullptr, nullptr);
}
Example above asserts because std::is_default_constructible<B>::value
is false, even though B
has a [private] default ctor and Foo<A,B>
is friend of B.
I will present a simplified example to make things easier. Then you can adapt it to your Foos class. The idea is to specialise my templated friend class as follows
#include <iostream>
// forward declaration
template <class... T>
struct Friend;
struct testing_tag;
// specialisation simply to check if default constructible
template <class T>
struct Friend<T, testing_tag> {
// sfinae trick has to be nested in the Friend class
// this candidate will be ignored if X does not have a default constructor
template <class X, class = decltype(X())>
static std::true_type test(X*);
template <class X>
static std::false_type test(...);
static constexpr bool value = decltype(test<T>(0))::value;
};
Notice that the std::true_type candidate will always be valid as long as X has a default constructor regardless if it is private, protected or public. Now test it
class default_public {
template <class... T>
friend struct Friend;
};
class default_protected {
template <class... T>
friend struct Friend;
protected:
default_protected() {}
};
class default_private {
template <class... T>
friend struct Friend;
private:
default_private() {}
};
class no_default {
public:
no_default(int x){}
};
// a convenient name to test with
template <class T>
using has_any_default_constructor = Friend<T, testing_tag>;
int main() {
std::cout << has_any_default_constructor<default_public>::value << std::endl;
std::cout << has_any_default_constructor<default_protected>::value << std::endl;
std::cout << has_any_default_constructor<default_private>::value << std::endl;
std::cout << has_any_default_constructor<no_default>::value << std::endl;
}
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