为什么 GCC 允许私有嵌套模板类/结构在全局模板函数中可见?

发布于 2024-09-24 14:13:49 字数 954 浏览 4 评论 0原文

我不明白为什么在下面的代码中,我可以创建函数 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 时都出现错误。

I don't understand why in the following code, I am allowed to create the function print_private_template while the compiler complains about 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;
}

Is this an expected behaviour? a compiler bug/extension?

Just to be clear, my goal is to make the compiler error on both the usage of print_private_template and print_private_class.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

屋檐 2024-10-01 14:13:49

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

ComeauTest.c(31):错误:类模板“A::B”(在第 7 行声明)无法访问
void print_private_template(const A::B &ab)
^
在基于“print_private_template”的实例化期间检测到
模板参数 <42U>在第 45 行

G++ 4.5 不会报告 -std=c++ -Wall -pedantic 的任何错误。

您的类 A::C 和类模板 A::B 都具有与任何其他普通成员相同的可见性。因此,print_private_classprint_private_template 都需要诊断。

11.8 嵌套类 [class.access.nest]

1 嵌套类是一个成员,因此具有与任何其他成员相同的访问权限。成员为
封闭类没有对嵌套类成员的特殊访问权限;通常的访问规则(第 11 条)
应当服从。

Comeau does give an error (when you comment out the print_private_class function and its call in strict C++03 mode.

ComeauTest.c(31): error: class template "A::B" (declared at line 7) is inaccessible
void print_private_template(const A::B &ab)
^
detected during instantiation of "print_private_template" based on
template argument <42U> at line 45

G++ 4.5 on Windows does not report any error with -std=c++ -Wall -pedantic though.

Your class A::C and class template A::B<T> both have the same visibility as any other normal members. Hence, both print_private_class and print_private_template require a diagnostic.

11.8 Nested classes [class.access.nest]

1 A nested class is a member and as such has the same access rights as any other member. The members of
an enclosing class have no special access to members of a nested class; the usual access rules (Clause 11)
shall be obeyed.

紫﹏色ふ单纯 2024-10-01 14:13:49

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

As stated by Dirk Gently, GCC doesn't perform access control when instantiating template structs / classes nested in other (template) structs / classes.

One way to work around this is to encapsulate them in a non-template struct:

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;

The last line will fail to compile with the error:

error: 'struct MyTemplate<1>::PT' is private within this context

I'll grant that this is ugly, especially having to use PT::template but it seems to effectively prevent clients from instantiating helper templates they aren't meant to access, so it's worth a shot.

不可一世的女人 2024-10-01 14:13:49

它在 GCC 11 中得到了修复

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

最小重现:

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

以上在 GCC 中失败,因为 f 是一个模板功能。

It got fixed for GCC 11

Ten years later... and the bug got fixed for GCC 11: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=41437#c13 (another point in the dupe pool had been previously linked to by dirkgently).

A minimal reproduction:

main.cpp

class Out {
  protected:
    class In {};
};

template <class C>
void f() { Out::In in; }

int main() {
    f<Out>();
}

still compiles in GCC 10.2 with all warnings enabled:

g++-10 -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp

but fails correctly in clang++ 10:

void f() { Out::In in; }
                ^
main.cpp:3:11: note: declared protected here
    class In {};
          ^
1 error generated

The above fails to fail in GCC because f is a template function.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文