最近我试图检测特定私有构造函数的存在,并遇到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无关的上下文中一样。仅考虑变量初始化的直接上下文的有效性。
“变量初始化的直接上下文”特别是讨论is_constructible_v
,它是一个变量模板,使用相同的参数初始化为is_constructible
的值。也就是说,初始化发生在代码之外,因此代码中获取所述变量值的上下文与构造函数的可访问性无关。无论从何处访问,获取的值都是相同的。
与第一句话一起,该标准有效地说“这只是寻找可公开获取的东西”。