具有非公共析构函数的std :: is_constructible类型

Com*_*sMS 11 c++ type-traits language-lawyer c++11

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

is_constructible对gcc和Visual C++(coliru上的gcc演示)进行最终检查都会失败.

这是标准所要求的行为吗?如果是这样,有没有办法检查类型是否具有特定的构造函数,无论析构函数上的访问说明符是什么?

Col*_*mbo 13

C++ 14 FD定义is_constructible如下:

给出以下函数声明:

template <class T>
add_rvalue_reference_t<T> create() noexcept;
Run Code Online (Sandbox Code Playgroud)

is_constructible<T, Args...>当且仅当以下变量定义适用于某些发明变量时,才应满足模板特化的谓词条件 t:

T t(create<Args>()...);
Run Code Online (Sandbox Code Playgroud)

执行访问检查就好像在与其无关的上下文T 中执行Args.仅考虑变量初始化的直接上下文的有效性.[ 注意:初始化的评估可能会导致副作用,例如类模板特化和函数模板特化的实例化,隐式定义函数的生成等等.这种副作用不在"直接背景"中,并且可能导致程序形成不良.- 尾注 ]

现在问题基本上简化为"析构函数是否在变量初始化的直接上下文中调用?" [class.dtor]/11:

隐式调用析构函数

  • 对于在程序终止时具有静态存储持续时间(3.7.1)的构造对象(3.6.3),
  • 对于具有自动存储持续时间(3.7.3)的构造对象,当创建对象的块退出时(6.7),
  • 当一个构造的临时对象的生命周期结束时(12.2).

在每种情况下,调用的上下文都是对象构造的上下文.

因此,析构函数调用是在构造的上下文中(这可能与此处的初始化同义),这意味着它被考虑并导致特征返回false.
我认为这是不明确的(例如,即时与非明确的直接上下文?),但直观地说,我希望符合标准的实现将表达标记NotDestructible()为格式错误 - 无论是SFINAE还是不友好(最好是前者).但是,从来没有良好的形式.
用libc ++,libstdc ++和GCC来表示它是无效的,SFINAE友好.


如果是这样,有没有办法检查类型是否具有特定的构造函数,无论析构函数上的访问说明符是什么?

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

演示.可以很容易地建立一致的特征:获取is_only_constructible特征并将其与之结合is_destructible(显然,后者false在与私有析构函数结合时返回).

  • @Columbo:也许,虽然我已经习惯了标准的超级模糊,但我还是停止推理实际措辞所暗示的内容,而是开始考虑委员会在撰写时的意图更有可能.最终结果是相同的("我不知道,我可能是错的"),但至少我通过不从一个模糊的段落反弹到另一个来节省一些神经生命:) (2认同)

And*_*owl 5

引用C++标准(草案N4296)的段落[meta.unary.prop]/7:

给出以下函数声明:

template <class T>
add_rvalue_reference_t<T> create() noexcept;
Run Code Online (Sandbox Code Playgroud)

is_constructible<T, Args...>当且仅当以下变量定义适用于某些发明变量时,才应满足模板特化的谓词条件t:

T t(create<Args>()...);
Run Code Online (Sandbox Code Playgroud)

换句话说,如果析构函数不可访问,则为is_constructible<T, Args...>::valueyield false.