std :: is_constructible立即上下文和朋友声明

问题描述 投票:1回答:2

最近我试图检测特定私有构造函数的存在,并遇到std::is_constructible只检查直接上下文的问题,因此不会识别任何这样的构造函数。经过一些研究后,我确实看到一个答案here提到正确的方法是与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的问题。在它们的实现中,不是使用别名模板到实际的struct std::is_constructible本身,而是直接调用内部使用的内部函数,而内部函数又忽略了friend声明。

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

因此,主要的问题是这个代码应该正常工作(因为它应该能够访问私有构造函数并传递断言),标准定义访问仅限于直接上下文吗?类似的问题也提出了here,我不确定的主要问题是在这种情况下“直接上下文”的确切定义,因为这与链接问题中的示例略有不同。

来自N4713的相关段落23.15.4.3.8 [meta.unary.prop] / 8:

执行访问检查就像在与T和任何Args无关的上下文中一样。仅考虑变量初始化的直接上下文的有效性。

c++ language-lawyer c++17 typetraits
2个回答
5
投票

经过一些研究后,我确实看到这里的一个答案提到正确的方法是用std::is_constructible与有问题的班级交流以允许它访问。

不,绝对不是。这根本不是正确的方法。无法保证这将起作用。

此外,无法保证friending标准库中的任何内容都能满足您的需求。标准库不是你的朋友。 P1339在Kona获得批准,并将更新SD-8,使标准库有权假设用户不这样做......并且图书馆不会关心更改是否会破坏这样的用户友谊。

std::is_constructible_v<A>是,而且应该是false


1
投票

“变量初始化的直接上下文”特别是讨论is_constructible_v,它是一个变量模板,使用相同的参数初始化为is_constructible的值。也就是说,初始化发生在代码之外,因此代码中获取所述变量值的上下文与构造函数的可访问性无关。无论从何处访问,获取的值都是相同的。

与第一句话一起,该标准有效地说“这只是寻找可公开获取的东西”。

© www.soinside.com 2019 - 2024. All rights reserved.