std::is_constructible 具有非 public 析构函数的类型
std::is_constructible on type with non-public destructor
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) 上都会失败。
这是标准要求的行为吗?如果是这样,有什么方法可以检查该类型是否具有特定的构造函数,而不考虑析构函数上的访问说明符?
引用 C++ 标准(草案 N4296)的第 [meta.unary.prop]/7 段:
Given the following function declaration:
template <class T>
add_rvalue_reference_t<T> create() noexcept;
the predicate condition for a template specialization is_constructible<T, Args...>
shall be satisfied if and only if the following variable definition would be well-formed for some invented variable t
:
T t(create<Args>()...);
换句话说,如果析构函数不可访问,is_constructible<T, Args...>::value
会产生 false
。
C++14 FD定义is_constructible
如下:
Given the following function declaration:
template <class T>
add_rvalue_reference_t<T> create() noexcept;
the predicate condition for a template specialization
is_constructible<T, Args...>
shall be satisfied if and only if the
following variable definition would be well-formed for some invented
variable t
:
T t(create<Args>()...);
Access checking is performed as if in a context unrelated to T
and any of the Args
. Only the validity of the immediate context of
the variable initialization is considered. [ Note: The evaluation
of the initialization can result in side effects such as the
instantiation of class template specializations and function template
specializations, the generation of implicitly-defined functions, and
so on. Such side effects are not in the “immediate context” and can
result in the program being ill-formed. —end note ]
现在问题基本上减少到 "Is the destructor call in the immediate context of the variable initialization?" [class.dtor]/11:
A destructor is invoked implicitly
- for a constructed object with static storage duration (3.7.1) at program termination (3.6.3),
- for a constructed object with automatic storage duration (3.7.3) when the block in which an object is created exits (6.7),
- for a constructed temporary object when its lifetime ends (12.2).
In each case, the context of the invocation is the context of the
construction of the object.
因此析构函数调用是在构造的上下文中(这里大概是初始化的同义词),这意味着它被考虑并导致特征 return false
.
我认为这是未指定的(例如直接与非明确直接上下文?),但直觉上我希望符合规范的实现将表达式 NotDestructible()
标记为格式错误 - SFINAE 友好与否(最好是前者).不过,从来没有合式。
Clang with libc++, libstdc++ and GCC do say that it's invalid, SFINAE-friendly.
If so, is there any way to check whether the type has a specific
constructor, regardless of the access specifier on the destructor?
使用 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
组合(显然后者 returns false
与私有析构函数组合时)。
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) 上都会失败。
这是标准要求的行为吗?如果是这样,有什么方法可以检查该类型是否具有特定的构造函数,而不考虑析构函数上的访问说明符?
引用 C++ 标准(草案 N4296)的第 [meta.unary.prop]/7 段:
Given the following function declaration:
template <class T> add_rvalue_reference_t<T> create() noexcept;
the predicate condition for a template specialization
is_constructible<T, Args...>
shall be satisfied if and only if the following variable definition would be well-formed for some invented variablet
:T t(create<Args>()...);
换句话说,如果析构函数不可访问,is_constructible<T, Args...>::value
会产生 false
。
C++14 FD定义is_constructible
如下:
Given the following function declaration:
template <class T> add_rvalue_reference_t<T> create() noexcept;
the predicate condition for a template specialization
is_constructible<T, Args...>
shall be satisfied if and only if the following variable definition would be well-formed for some invented variablet
:T t(create<Args>()...);
Access checking is performed as if in a context unrelated to
T
and any of theArgs
. Only the validity of the immediate context of the variable initialization is considered. [ Note: The evaluation of the initialization can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the “immediate context” and can result in the program being ill-formed. —end note ]
现在问题基本上减少到 "Is the destructor call in the immediate context of the variable initialization?" [class.dtor]/11:
A destructor is invoked implicitly
- for a constructed object with static storage duration (3.7.1) at program termination (3.6.3),
- for a constructed object with automatic storage duration (3.7.3) when the block in which an object is created exits (6.7),
- for a constructed temporary object when its lifetime ends (12.2).
In each case, the context of the invocation is the context of the construction of the object.
因此析构函数调用是在构造的上下文中(这里大概是初始化的同义词),这意味着它被考虑并导致特征 return false
.
我认为这是未指定的(例如直接与非明确直接上下文?),但直觉上我希望符合规范的实现将表达式 NotDestructible()
标记为格式错误 - SFINAE 友好与否(最好是前者).不过,从来没有合式。
Clang with libc++, libstdc++ and GCC do say that it's invalid, SFINAE-friendly.
If so, is there any way to check whether the type has a specific constructor, regardless of the access specifier on the destructor?
使用 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
组合(显然后者 returns false
与私有析构函数组合时)。