我不明白为什么在下面的代码中,我可以在编译器抱怨print_private_template
时创建函数print_private_class
:
#include <cstdio>
class A
{
private:
template <unsigned T>
struct B
{
};
struct C
{
};
public:
template <unsigned T>
B<T> getAb()
{
return B<T>();
}
C getAc()
{
return C();
}
};
template<unsigned T>
void print_private_template(const A::B<T> &ab)
{
printf("%d\n", T);
}
void print_private_class(const A::C &ac)
{
printf("something\n");
}
int main(int, char**)
{
A a;
print_private_template(a.getAb<42>());
print_private_class(a.getAc());
return 0;
}
这是预期的行为吗?编译器错误/扩展?
为了清楚起见,我的目标是使上的编译器错误使用print_private_template
和print_private_class
。
答案 0 :(得分:2)
Comeau确实会出错(当您在严格的C ++ 03模式下注释掉print_private_class
函数及其调用时。
ComeauTest.c(31):错误:类模板“A :: B”(在第7行声明)无法访问 void print_private_template(const A :: B&amp; ab) ^ 在基于的“print_private_template”实例化期间检测到 模板参数&lt; 42U&gt;第45行
Windows上的G ++ 4.5不会报告-std=c++ -Wall -pedantic
的任何错误。
您的班级A::C
和班级模板A::B<T>
都具有与其他正常成员相同的可见度。因此,print_private_class
和print_private_template
都需要诊断。
11.8嵌套类 [class.access.nest]
1 嵌套类是成员,因此具有与任何其他成员相同的访问权限。的成员 封闭类对嵌套类的成员没有特殊访问权限;通常的访问规则(第11条) 应该遵守。
答案 1 :(得分:1)
它已针对GCC 11修复
十年后...并且GCC 11的错误已修复:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=41437#c13(dirkgently先前已将dupe池中的另一点链接到了该点)。
最小复制:
main.cpp
class Out {
protected:
class In {};
};
template <class C>
void f() { Out::In in; }
int main() {
f<Out>();
}
仍在GCC 10.2中编译并启用所有警告:
g++-10 -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
但在clang++
10中正确失败:
void f() { Out::In in; }
^
main.cpp:3:11: note: declared protected here
class In {};
^
1 error generated
由于f
是模板函数,因此上述操作在GCC中失败。
答案 2 :(得分:0)
如Dirk Gently所述,GCC在实例化嵌套在其他(模板)结构/类中的模板结构/类时不执行访问控制。
解决此问题的一种方法是将它们封装在非模板结构中:
template<int I> class MyTemplate
{
struct PT
{
template<int, typename = void> struct InnerTemplate;
// ... specialisations here ...
};
public:
typedef typename PT::template InnerTemplate<I>::SomeType SomeType;
};
typedef MyTemplate<1>::PT::InnerTemplate<1> ThisWontWork;
最后一行将无法编译并出现错误:
error: 'struct MyTemplate<1>::PT' is private within this context
我会认为这很难看,尤其是必须使用PT::template
,但它似乎有效地阻止了客户端实例化他们不打算访问的帮助模板,因此值得一试。