如何检查类是否具有默认构造函数(public,protected或private)

shr*_*ike 8 c++ c++11 c++14

我需要检查一个类C是否有一个默认的构造函数,无论是隐式的还是自定义的,或者是public,protected或者private.

我尝试使用std::is_default_constructible<C>::value,如果返回真C有一个public默认的构造函数(隐式或自定义),但false如果C有一个protectedprivate默认的构造函数(接缝是标准的行为虽然).

有没有办法检查一个类是否有一个protectedprivate默认的构造函数?

注意(如果这可能有帮助):检查是从要检查friend的类的函数执行的C.


我需要执行此检查,以便默认构造对应于元组nullptr指针的对象,对象的m_objs成员Foo(下面的部分Foo定义):

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;
};
Run Code Online (Sandbox Code Playgroud)

它旨在用作:

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);
}
Run Code Online (Sandbox Code Playgroud)

上面的例子断言因为std::is_default_constructible<B>::value是假的,即使B有[私人]默认ctor并且Foo<A,B>是B的朋友.

lin*_*ver 5

我将展示一个简化的例子,让事情变得更容易。然后你可以将它调整到你的 Foos 类。这个想法是专门化我的模板化朋友类如下

#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;
};
Run Code Online (Sandbox Code Playgroud)

请注意,只要 X 具有默认构造函数,无论它是私有的、受保护的还是公共的,std::true_type 候选对象将始终有效。现在测试一下

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;
}
Run Code Online (Sandbox Code Playgroud)