4

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

4

3 回答 3

2

Comeau确实给出了一个错误(当您在严格的 C++03 模式下注释掉print_private_class函数及其调用时。

ComeauTest.c(31): error: class template "A::B" (declared at line 7) is inaccessible在第 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 条)。

于 2010-09-24T06:30:21.760 回答
1

正如 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,但它似乎有效地阻止了客户实例化他们不打算访问的帮助模板,所以值得一试。

于 2017-09-26T13:25:33.047 回答
1

它已针对 GCC 11 修复

十年后......并且为 GCC 11 修复了该错误:https ://gcc.gnu.org/bugzilla/show_bug.cgi?id=41437#c13 (欺骗池中的另一个点之前已由dirkgently链接到)。

最小复制:

主文件

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

以上在 GCC 中失败,因为f是模板函数。

于 2020-11-24T11:32:42.553 回答