std::is_constructible 为私有构造函数返回不一致的值

zen*_*hoy 13 c++ type-traits

std::is_constructible处理私有构造函数的规则是什么?鉴于以下代码:

#include <iostream>

class Class {
private:
    Class() { }
};

template <typename T>
class Test {
public:
    static void test() {
        std::cout
            //<< std::is_constructible<Class>::value
            << std::is_constructible<T>::value
            << std::endl;
    }
};

int main() {
    Test<Class>::test();
}
Run Code Online (Sandbox Code Playgroud)

这会打印0( ideone ),即T默认不可构造。

取消注释注释行,它会打印11ideone),因此T突然变得默认可构造。

我可以找到支持这两个结果的推理,但我不明白包含注释行如何改变第二个结果。这是以某种方式调用UB吗?这是编译器错误吗?还是std::is_constructible真的那么矛盾?

mut*_*oid 3

std::is_constructible在这种情况下应该返回,false因为构造函数不可访问。

正如问题下方所指出的,问题中描述的行为是由 GCC / libstdc++ 中的错误引起的。该错误在这里报告,并且根据 Bugzilla 的说法,如果不是由模板函数中的类的访问控制错误引起的,该错误已经有一段时间未解决了。这两个 bug 之间的关系取自 Jonathan Wakely 的 Bugzilla 评论,他似乎首先发现了这两个 bug 之间的联系。

当删除构造函数而不是使其私有时,GCC 中此场景的行为变得正确,这一事实也暗示了这一点:

class Class {
    Class() = delete;
};
Run Code Online (Sandbox Code Playgroud)

分别打印出000。这是正确的输出(clang在使用私有构造函数的情况下也能正确报告)。

这可以解释在行中注释时 观察到的行为变化,因为在模板化结构的函数内部,访问检查不起作用,并报告构造函数可以访问,而实际上却不能访问。当在下一行或可能在完全不同的位置再次检查特征时(如此处的情况,它已经被实例化,因此会产生错误的答案。