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

时间:2016-05-13 13:33:22

标签: c++ c++11 c++14

我需要检查一个类C是否有默认构造函数(隐式或自定义),以及publicprotectedprivate

我尝试使用std::is_default_constructible<C>::value,如果Cpublic默认构造函数(隐式或自定义),则返回true;如果falseC,则返回protected privateprotected默认构造函数(虽然接缝是标准行为。)

有没有办法检查某个类是否有privatefriend默认构造函数?

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

我需要执行此检查,以便默认构造对象m_objs元组的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; }; 对象的成员(下面的部分Foo定义):

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);
}

旨在用作:

std::is_default_constructible<B>::value

上面的示例断言,因为B为false,即使Foo<A,B>有[私有]默认ctor且FUNCTION FNC_LST_OUR(p_code varchar2, p_pm_from varchar2, p_pm_to varchar2 ) return VARCHAR2 is v_sql2 VARCHAR2(30000) := ''; v_sql VARCHAR2(30000) := ''; number_out NUMBER := 0; error_msg_tmp varchar2(255); begin v_sql := 'select s.com_code, s.pn_code, count(*) as our from pmtest s inner join PMOP_TEST l on s.com_code=l.com_code and s.pn_code=l.pn_code where s.com_code = ''' || p_code || '; if p_pm_from is not null then v_sql := v_sql || ' and s.pn_code between ''' || p_pm_from || ''' and ''' || p_pm_to || ''''; end if; v_sql := v_sql || ' group by s.com_code,s.pn_code having count(s.pn_code)> 0 '; EXECUTE IMMEDIATE v_sql INTO v_sql2; RETURN v_sql2; exception when OTHERS THEN error_msg_tmp := substr(sqlcode || ' - ' || sqlerrm, 1, 200); RETURN v_sql2; end; 是B的朋友。

3 个答案:

答案 0 :(得分:3)

问题是如果一个类既没有public,也没有protected也没有private默认构造函数,那么实例的简单默认定义会产生编译错误,而不是运行时异常。因此测试很简单:如果朋友函数C c;中的此表达式编译,则该类具有默认的ctor,public,protected或private。

只看示例代码:

#include <iostream>
#include <string>

class Cwith {
private:
    std::string name;
    Cwith(): name("default ctor") {}
    friend void build();
};

class Cwithout {
private:
    std::string name;
    Cwithout(const std::string& name): name(name) {};
    friend void build();
};

void build() {
    Cwith cw;
    std::cout << cw.name << std::endl;
    Cwithout cwo;   // error : class Cwithout has no defaut constructor
    std::cout << cwo.name << std::endl;
}

int main() {
    build();
    return 0;
}

但我无法想象一次运行时测试...

答案 1 :(得分:3)

我的理解是你要检查你的friend是否可以默认构建一个类。诀窍是你必须在friend函数的范围内具有SFINAE 。为此,您需要模板。要拥有本地模板,您需要通用lambdas。

我们从一个overloader开始,我们可以将多个lambda传递给。可能有更好的方法来写这个:

template <class... Fs>
struct overload {
    void operator()();
};

template <class F, class... Fs>
struct overload<F, Fs...> : F, overload<Fs...> {

    overload(F&& f, Fs&&... fs)
    : F(std::forward<F>(f))
    , overload<Fs...>(std::forward<Fs>(fs)...)
    { }

    using F::operator();
    using overload<Fs...>::operator();
};

template <class... Fs>
overload<std::decay_t<Fs>...> make_overload(Fs&&... fs) {
    return {std::forward<Fs>(fs)...};
}

然后你传入重载的,通用的,SFINAE-d lambdas(需要C ++ 14)。我们说我们有:

struct Q {
    friend void foo();
};

template <class T>
struct tag_t { using type = T; };

template <class T>
constexpr tag_t<T> tag{};

然后我们可以写:

void foo() {
    auto f = make_overload(
        [](auto x) -> decltype( typename decltype(x)::type(), void() ) { 
            Q q;
            std::cout << "I can do it.\n";
        },
        [](...) {
            std::cout << "What do you want here?\n";
        });

    f(tag<Q>, 0); 
}

如果works是朋友,那么第一个重载是可行的,也是首选的 - 所以你得到它,因为它可以构造一个Q。如果works不是朋友,则第一次重载不可行,因此您获得第二次重载。

关键是我们在Q内测试typename decltype(x)::type()works()部分)的构造 - 所以它将被友谊覆盖。

因此,对于您的具体用法,那将是:

template <class Obj>
objs_ctor() {
    Obj*& obj = std::get<Obj*>(m_objs);

    auto ctor = make_overload(
        [&](auto x) -> decltype( typename decltype(x)::type(), void() ) { 
            if (!obj) {
                obj = new Obj;
            }
        },
        [=](...) {
            assert(obj);
        });

    ctor(tag<Obj>);
}

答案 2 :(得分:3)

我将提供一个简化示例,以简化操作。然后你可以适应你的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;
};

请注意,只要X具有默认构造函数,std :: true_type候选者将始终有效,无论它是private,protected还是public。现在测试一下

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;
}