我需要检查一个类C
是否有默认构造函数(隐式或自定义),以及public
,protected
或private
。
我尝试使用std::is_default_constructible<C>::value
,如果C
有public
默认构造函数(隐式或自定义),则返回true;如果false
有C
,则返回protected
private
或protected
默认构造函数(虽然接缝是标准行为。)
有没有办法检查某个类是否有private
或friend
默认构造函数?
注意(如果这可能有帮助):检查是从要检查的类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的朋友。
答案 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;
}