【问题标题】:Why does GCC allow private nested template classes/structs to be visible from global template functions?为什么 GCC 允许私有嵌套模板类/结构从全局模板函数中可见?
【发布时间】:2010-09-24 06:14:58
【问题描述】:

我不明白为什么在下面的代码中,我被允许创建函数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;
}

这是预期的行为吗?编译器错误/扩展?

为了清楚起见,我的目标是让编译器在 both 使用 print_private_templateprint_private_class 时出错。

【问题讨论】:

  • 两者都在MSVC2008中触发编译器错误

标签: c++ templates private-members


【解决方案1】:

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

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

不过,Windows 上的 G++ 4.5 不会使用 -std=c++ -Wall -pedantic 报告任何错误。

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

11.8 嵌套类 [class.access.nest]

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

【讨论】:

  • 我认为我在 GCC 中发现了一个编译器错误?
  • IIRC,GCC 4.5(我正在使用的)是一个实验版本。执行质量必然存在一些问题。但是,当然可以,您可以继续提交。
  • 我使用的是 GCC 4.4.3,所以我怀疑问题出在你不稳定的版本上。
  • 哇,这似乎是一个非常古老的错误!我可以从 GCC 3.4 及更高版本复制它!不过,GCC 3.3 错误是应该的。
  • 嗯。直到最近,与大多数编译器一起使用内部类一直很痛苦。我看到你已经提交了一个错误(gcc.gnu.org/bugzilla/show_bug.cgi?id=45775 其他人)。希望这个问题很快得到解决!
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    已针对 GCC 11 修复

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

    最小复制:

    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 是一个模板函数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-01
      • 2011-02-02
      • 2013-09-05
      • 1970-01-01
      • 2015-07-03
      • 1970-01-01
      相关资源
      最近更新 更多