私有模板类/结构可见性

时间:2010-09-24 06:14:59

标签: c++ templates private-members

我不明白为什么在下面的代码中,我可以在编译器抱怨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_templateprint_private_class

3 个答案:

答案 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_classprint_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#c13dirkgently先前已将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,但它似乎有效地阻止了客户端实例化他们不打算访问的帮助模板,因此值得一试。