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


13

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();
}

此打印0ideone),即T默认情况下不可构造。

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

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


1
看起来像是GCC错误,00
c声有

1
在使用c ++ 17 g ++ 9.2.1 / g ++-10.0在我的机器上编译并将std :: is_constructible <...> :: value替换为is_constructible_v <...>时,我注意到另一个奇怪的想法是结果更改为00
mutableVoid

1
@mutableVoid确实-似乎该::value版本也能够更改之前版本的输出:godbolt.org/z/zCy5xU取消注释行,在gcc中所有注释均变为1:s。
Ted

1
修复它的另一种方法:godbolt.org/z/EKaP3r因此,基本上,这是某种评估命令错误。
Marek R

2
@mutableVoid您甚至不需要实例化函数模板即可使其变为真实。在此示例中,它返回,false但是如果未注释功能模板,则它突然返回truegodbolt.org/z/zqxdk2
Ted

Answers:


3

std::is_constructiblefalse在这种情况下应该返回,因为构造器不可访问。

如问题下方所指出的那样,问题中描述的行为是由GCC / libstdc ++中的错误引起的。该错误已在此处报告,并且据Bugzilla所述,与如果不是由模板功能中的访问控制错误引起的,而该错误已经解决了很长时间。这两个错误之间的关系来自乔纳森·韦克利(Jonathan Wakely)的Bugzilla评论,该评论似乎首先检测到这两个错误之间的联系。

这也暗示了以下事实:删除构造函数而不是使其私有化后,GCC中此方案的行为变得正确:

class Class {
    Class() = delete;
};

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.