std::is_constructible 直接上下文和友元声明

std::is_constructible immediate context and friend declarations

最近我试图检测特定私有构造函数的存在,并 运行 解决 std::is_constructible 仅检查直接上下文的问题,因此不会识别任何此类构造函数。经过一番研究后,我确实看到一个答案 提到正确的方法是将有问题的 class 与 std::is_constructible 交友以允许其访问。

为了测试此方法是否有效,我尝试了以下测试代码

#include <type_traits>

class A {
private:
  template<typename, typename ...>
  friend struct std::is_constructible;

  A() = default;
};

int main() {
  static_assert(std::is_constructible<A>::value);
  static_assert(std::is_constructible_v<A>);
}

有趣的是,这种方法在 Visual Studio 2017 年似乎确实适用于 std::is_constructible,尽管我随后开始遇到 std::is_constructible_v 的问题。在他们的实现中,他们没有对实际结构 std::is_constructible 本身使用别名模板,而是直接调用内部使用的内在函数,这反过来又忽略了 friend 声明。

认为这是他们的标准库实现的一个错误,然后我在其他编译器中进行了测试,发现 clang 和 gcc 在任何情况下都无法通过这个断言,这让我想知道它是否应该通过完全像这样工作(链接 post 上的一些评论似乎暗示这是一个错误,而其他人则说它不应该考虑朋友声明)。

因此,主要问题是这段代码是否应该按照标准定义的访问被限制在直接上下文中的方式正确工作(比如它是否应该能够访问私有构造函数并传递断言)?还提出了一个类似的问题 ,我不确定的主要是 "immediate context" 在这种情况下的确切定义,因为这与链接问题中的示例略有不同。

来自N4713 23.15.4.3.8 [meta.unary.prop]/8:

的相关段落

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.

After some research I did see that one answer here mentioned that the proper way is to friend the class in question with std::is_constructible to allow it to have access.

没有。当然不。这根本不是正确的方法。不能保证这会有效。

此外,无法保证 friending 标准库中的任何内容 都可以按照您的意愿执行。标准库不是你的朋友P1339 was approved in Kona and will update SD-8 赋予标准库假设用户不会这样做的权利...并且库不会在意更改是否会像这样破坏用户友谊。

std::is_constructible_v<A> 是并且应该是 false.

中的"immediate context of the variable initialization"具体讲的是is_constructible_v,它是一个变量模板,初始化为is_constructible的值,参数相同。也就是说,初始化发生在代码之外,因此代码中获取所述变量值的上下文与构造函数的可访问性无关。无论从哪里访问,获取的值都是一样的。

加上第一句,标准实际上是说 "this only looks for publicly accessible stuff"。