【问题标题】:std::is_constructible returns inconsistent value for private constructorstd::is_constructible 为私有构造函数返回不一致的值
【发布时间】:2020-03-02 14:08:25
【问题描述】:

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

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

取消注释注释行,它会打印11 (ideone),所以T 突然变成了默认构造。

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

【问题讨论】:

  • 看起来像一个 GCC 错误,clang 9 prints 00
  • 在我的机器上使用 c++17 g++9.2.1 / g++-10.0 编译并将 std::is_constructible<...>::value 替换为 is_constructible_v,那是result changes to 00
  • @mutableVoid 确实——而且似乎::value 版本也能够改变之前的输出:godbolt.org/z/zCy5xU 取消注释行并且在 gcc 中全部变为 1:s。
  • 另一种修复方法:godbolt.org/z/EKaP3r 所以基本上这是某种评估顺序错误。
  • @mutableVoid 你甚至不需要实例化函数模板来实现它。在这个例子中,它返回false,但是如果函数模板被取消注释,它突然返回truegodbolt.org/z/zqxdk2

标签: c++ typetraits


【解决方案1】:

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

正如问题下方所指出的,问题中描述的行为是由 GCC / libstdc++ 中的错误引起的。该错误是reported here,根据Bugzilla 的说法,如果不是由access control bug for classes in template functions 引起的话,该错误已经很久没有解决了。这两个 bug 之间的关系取自 Jonathan Wakely 的 Bugzilla 评论,他似乎首先检测到了这两个 bug 之间的联系。

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

class Class {
    Class() = delete;
};

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

这可以解释observed change of behavior 在该行中的注释,因为在 templated 结构中的函数内部,访问检查不起作用并报告构造函数可访问,但实际上它不是。当在下一行或可能在完全不同的位置再次检查特征时(如here 的情况),它已经被实例化,因此会产生错误的答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-30
    • 2021-01-13
    • 2012-08-07
    • 2019-02-27
    • 2019-10-16
    相关资源
    最近更新 更多