对于具有私有或受保护的析构函数的类型,std::is_constructible
的预期结果是什么?
例如,我仍然可以在堆上构造这样的对象,即使只有朋友可以释放它:
#include <type_traits>
class Foo
{
friend void freeFoo(Foo*);
public:
Foo()
{}
private:
// Destructor is private!
~Foo()
{}
};
void freeFoo(Foo* f)
{
delete f; // deleting a foo is fine here because of friendship
}
int main()
{
Foo* f = new Foo();
// delete f; // won't compile: ~Foo is private
freeFoo(f); // fine because of friendship
if(!std::is_constructible<Foo>::value)
{
std::cout << "is_constructible failed" << std::endl;
}
}
is_constructible
的最终检查将在gcc和Visual C ++(gcc demo on coliru)上失败。
这是标准所要求的行为吗?如果是这样,有没有办法检查类型是否具有特定的构造函数,而不管析构函数上的访问说明符是什么?
答案 0 :(得分:13)
C ++ 14 FD定义is_constructible
如下:
给出以下函数声明:
template <class T> add_rvalue_reference_t<T> create() noexcept;
模板特化的谓词条件 当且仅当,
is_constructible<T, Args...>
才会得到满足 对于一些发明的人来说,下面的变量定义会很好 变量t
:T t(create<Args>()...);
执行访问检查,就像在与
T
无关的上下文中一样 和任何Args
。只有直接上下文的有效性 考虑变量初始化。 [注意:评估 初始化可能导致副作用,如 类模板特化和函数模板的实例化 专业化,隐式定义函数的生成,以及 等等。这种副作用不在“直接背景”中,并且可以 导致程序格式不正确。 -end note ]
现在问题基本上减少到&#34;析构函数是否在变量初始化的直接上下文中调用?&#34; [class.dtor] / 11:
隐式调用析构函数
- 表示在程序终止时具有静态存储持续时间(3.7.1)的构造对象(3.6.3),
- 对于具有自动存储持续时间(3.7.3)的构造对象,当创建对象的块退出时(6.7),
- 表示构造的临时对象的生命周期结束时(12.2)。
在每种情况下,调用的上下文都是上下文 构建对象。
因此析构函数调用位于构造的上下文中(这可能与此处的初始化同义),这意味着它被考虑并导致特征返回false
。
我认为这是不明确的(例如,即时与非显式直接上下文?),但直觉上我希望符合标准的实现将表达式NotDestructible()
标记为格式错误 - 无论是SFINAE还是非友好(最好是前者) )。但是,从来没有良好的形式
Clang with libc++, libstdc++ and GCC do say that it's invalid, SFINAE-friendly
如果是,有没有办法检查类型是否具有特定类型 构造函数,不管析构函数的访问说明符是什么?
如何使用new
?
template <typename T, typename... Args>
class is_only_constructible
{
template <typename, typename=void> struct test : std::false_type {};
template <typename U>
struct test<U, decltype(void(new U(std::declval<Args>()...)))> : std::true_type {};
public:
static constexpr bool value = test<T>::value;
};
Demo。可以轻松建立一致的特征:获取is_only_constructible
特征并将其与is_destructible
结合使用(当与私有析构函数结合使用时,显然后者返回false
。)
答案 1 :(得分:5)
引用C ++标准(草案N4296)的段落[meta.unary.prop] / 7:
给出以下函数声明:
template <class T> add_rvalue_reference_t<T> create() noexcept;
当且仅当以下变量定义适用于某个发明变量
is_constructible<T, Args...>
时,才应满足模板特化t
的谓词条件:T t(create<Args>()...);
换句话说,如果析构函数不可访问,is_constructible<T, Args...>::value
会产生false
。