C++编译器在封装行为上存在分歧 - 哪一个做对了?
C++ compilers diverge in encapsulation behavior - which one gets it right?
编译器(clang-5.0.0
,GCC-7.3
,ICC-18
和MSVC-19
)在下面A
成员的可访问性方面有所不同。
class A {
template <class> static constexpr int f() { return 0; }
template <int> struct B {};
template <class T> using C = B<f<T>()>;
};
实际上,请考虑以下用法:
template <class T> using D = A::C<T>;
int main() {
// | clang | gcc | icc | msvc
(void) A::f<int>(); // 1: | f | f | f | f, (C)
(void) A::B<0>{}; // 2: | B | | B | B, (C)
(void) A::C<int>{}; // 3: | C, f | | C | C
(void) D<int>{}; // 4: | f | | C | C
}
右表显示了每个编译器需要公开哪些成员才能接受代码(为 C++14 编译时)。
恕我直言,ICC 和 MSVC(忽略(C)
条目)看起来是正确的。除了第一行,GCC似乎完全忽略了可访问性。
我不同意 clang 要求f
公开以实例化A::C<int>
和D<int>
。像ICC和MSVC一样,我认为C
,只有C
需要公开。确实C
使用f
但它不是实现细节吗?请注意,C
也使用B
。如果叮当是正确的,那么为什么它不要求B
也是公开的呢?
最后,让我们考虑(C)
条目。MSVC要求C
在第一次遇到D
的定义时是公开的,也就是说,MSVC抱怨C
是私有的。
我的问题是:
- 我的分析是对的(ICC也是)吗?否则,还有哪个编译器是正确的,为什么?
- MSVC问题是否又是 MSVC 中的两阶段实例化错误?
更新:关于 GCC,这似乎是评论 8 中报告的错误。
A::f<int>()
和A::B<0>
的问题很容易回答。f
和B
是私有的,也没有任何其他有趣的依赖项。访问它们的格式应该不正确。gcc 通常对模板中的访问控制非常宽容,在各种情况下都有一个未完成的元错误(我认为所有这些都是 gcc 允许在不应该访问时访问的形式,而不是在应该允许访问时禁止访问)。
A::C<int>
的问题更有趣。这是一个别名模板,但我们实际上在什么上下文中查看别名?它是在A
范围内(在这种情况下,使C
可访问就足够了)还是在使用它的上下文中(在这种情况下,f
、B
和C
都需要可访问)。这个问题正是CWG 1554,它仍然有效:
从 17.6.7 [temp.alias] 的当前措辞中不清楚别名模板和访问控制的交互。例如:
template <class T> using foo = typename T::foo; class B { typedef int foo; friend struct C; }; struct C { foo<B> f; // Well-formed? };
B::foo
替换为foo<B>
是在友C
类的上下文中完成的,使引用格式良好,还是独立于别名模板专用化的上下文确定访问权限?如果这个问题的答案是访问是独立于上下文确定的,则必须注意确保访问失败仍被视为"在函数类型的直接上下文中"(17.9.2 [temp.deduct] 第 8 段),以便导致扣除失败而不是硬错误。
尽管问题仍然悬而未决,但方向似乎是:
CWG的共识是,别名模板的实例化(查找和访问)应与其他模板一样,在定义上下文中,而不是在使用它们的上下文中。但是,它们仍应立即扩大。
也就是说,只有C
需要公开,f
和B
可以保持私密。这就是ICC和MSVC的解释。Clang有一个错误,允许别名模板规避访问(15914),这就是为什么clang要求f
可访问但不能B
。但除此之外,clang 似乎在使用点而不是定义点扩展别名。
D<int>
的问题应该完全遵循A::C
,CWG 1554 在这里没有问题。Clang是唯一一个在A::C
和D
之间具有不同行为的编译器,同样是由于错误15914。
总而言之,A::C
问题是一个开放的核心语言问题,但ICC在这里实现了语言的预期含义。其他编译器在访问检查和模板方面都存在问题。
- boost::asio::steady_timer()与sleep()我应该使用哪一个
- 我是C++编程的新手,这些代码之间有什么区别,我应该使用哪一个
- 替换密码:哪一个?
- For-loop或std::any_of,我应该使用哪一个?
- 哪一个是最好的方法类或结构?在 C++ 中
- 静态常量与常量局部变量,哪一个性能更好
- 一个互斥锁与多个互斥锁.哪一个更适合线程池?
- cv::String 和 std::string:何时使用哪一个以及必须同时使用两者?
- 哪一个对物体检测更快?
- 哪一个更适合存储字符、矢量<char>或字符串?
- Visual C++ 和 gcc 之间从 std::isblank 返回不一致.哪一个错了
- 在 C 和 C++ 编程中使用哪一个更好?
- 这两者中的哪一个是实现标头的正确方法
- 带大小参数和不带大小参数的"运算符删除":当两者都可用时,选择哪一个?
- C++编译器在封装行为上存在分歧 - 哪一个做对了?
- 对于初学者来说,我应该学习" c or c++ "之间的哪一个才能使用Arduino UNO?
- MongoC ++驱动程序BSON构造:基于流与基于字符串解析.哪一个性能更好?
- 这些指针中的哪一个需要免费()或delete()
- 当移动和复制构造函数都存在时,将调用哪一个
- GCC、Clang和IBM在如何执行依赖模板参数的名称查找方面存在分歧.哪一个是对的