【问题标题】:A C++ syntax question involving non trivial templating and friend declaration一个涉及非平凡模板和友元声明的 C++ 语法问题
【发布时间】:2010-01-31 19:08:39
【问题描述】:

以下代码应该是不言自明的。关于使用的语法(这是必须使用的语法),我有两个问题。如果您能为我提供这些问题的答案,我将永远感激不尽。

template <typename T>
struct A {
    template <typename S>
    void f (const A<S> &s);

    template <typename S>
    friend struct A; 
    // Question 1: why isn't the syntax 'friend struct A<S>' ? 
    // The semantic would stay, since we would like A<S> (for ANY S) to be friend of every A<T>..

    private:
        void g () const {}
};

template <typename T> 
template <typename S> // Question 2: Why can't the syntax be 'template <typename T, typename S>' ?
void A<T>::f (const A<S> &s) {
    s.g();
}

int main () {
    A<bool> abool;
    A<char> achar;

    abool.f(achar);
}

我已经验证这确实是唯一正确的语法(我很高兴发现我弄错了)。我的问题更多是关于语法背后的推理,如问题正文中所述。

感谢您的帮助。

【问题讨论】:

    标签: c++ templates syntax friend


    【解决方案1】:

    为什么不是语法...

    为什么语法不能...

    你希望我们说什么?决定这种语法的人(主要是 Stroustrup 本人,AFAIK)认为他们的语法比你的好。

    我不知道哪个更好或更容易记住 - 但我确实发现他们的比你的更有意义。当然,你可以不同意。

    编辑:好的,Alexander has nicely answered question #2。关于#1:

    不同之处在于A&lt;S&gt; 命名了一个类型,这是函数参数所期望的,而A 本身就是一个模板的名称 , 从中创建类型,如果你想成为 template 而不是类型的朋友,这很有意义:

    template <typename S>
    void f (const A<S> &s); // A<S> being the name of a type
    
    template <typename S>
    friend struct A; // A being the name of a template
    

    可以与特定模板实例而不是整个模板成为朋友,但为此模板必须在@处已被编译器知道(即声明) 987654325@声明:

    template< typename T >
    class foo;
    
    class bar {
      friend class foo<int>; // foo<int> being the name of a specific instance of foo
    };
    

    因此,与 模板 成为朋友是一个例外(“通常的”friend 声明声明了一个函数或类)并且确实需要不同的语法。

    【讨论】:

    • 我要问的不是语法本身,而是它与我猜想的不同——从查看语言的其余部分来看。也许你不同意,这 - 正如你自己所说 - 很好。
    • 我认为friend 语法与模板定义和声明 (template&lt;class S&gt; class A;) 和模板模板参数 (template&lt;template&lt;class S&gt; class A&gt; class C {};) 等其他类似结构非常吻合。
    【解决方案2】:

    虽然我不能说为什么选择了这种语法,但我只能说我会支持语言设计者做出的这两个决定——它们对我来说很有意义。在问题 2 中,您不仅有一个模板,还有两个嵌套的模板级别。为什么定义模板类的模板成员的语法应该隐藏这个事实?这样,它只是对现有模板语法的重新组合,而您的需要特殊规则才能将嵌套模板的模板参数合并到一个 template&lt;&gt; 中。

    【讨论】:

    • 您对问题二的回答似乎是合理的,谢谢。但是,问题 1 的语法对我来说似乎很离谱。更是如此,因为模板参数 (typename S) 根本没有在朋友声明中使用。
    • 另外,我认为这个系统是必要的:它决定了模板参数的类型,同时仍然是依赖的。即参数类型有一个模板子句嵌套和该子句中的一个位置:template&lt;typename A, typename B&gt; template&lt;typename C&gt; 在其中A#dependent-0-0B#dependent-0-1C#dependent-1-0。虽然我从未实现过 C++ 编译器,但我相信我们需要这种明确的模式来将类外定义与它们所属的模板相关联。
    【解决方案3】:

    假设您的嵌套模板声明稍微复杂一点:

    template <typename T, int I>
    struct A {
        template <typename S, I>
        void f (const A<S, I> &s);
    
        template <typename S, int J>
        friend struct A; 
        // Question 1: why isn't the syntax 'friend struct A<S, J>' ? 
        // The semantic would stay, since we would like A<S, J> (for ANY S, J combination) to be friend of every A<T, I>..
    
        private:
            void g () const {}
    };
    
    template <typename T, int I> 
    template <typename S> // Question 2: Why can't the syntax be 'template <typename T, int I, typename S>' ?
    void A<T>::f (const A<S> &s) {
        s.g();
    }
    
    int main () {
        A<bool, 5> abool;
        A<char, 7> achar;
    
        abool.f(achar);
    }
    

    突然间,您的建议似乎不再那么合理或明显了。哪一组参数先出现?假设您使用的是 C++0x 并且有一个变量参数列表?

    至于朋友声明,通过使用您提出的语法 (friend struct &lt;S, J&gt;),您突然让编译器不得不推断出 SJ 是作为模板参数,不应该从一些随机的范围。假设有人在与struct A 相同的范围级别上引入了一个类型S?声明friend struct A&lt;S,J&gt; 指的是哪个S?编译器怎么知道?在外部作用域中引入名称以从根本上改变嵌套作用域中声明的含义是否合理?

    如果你的意思是声明应该是:template &lt;typename S, int J&gt; friend struct A&lt;S, J&gt;,那么为什么朋友转发模板声明看起来与标准模板声明有什么不同呢?当您已经在 template &lt;typename S, int J&gt; 部分中提到它们时,在模板名称之后包含模板变量的名称是多余的。

    我还认为您建议的语法会使弄清楚模板专业化正在做什么变得更加困难,因为您必须查看代码的更多部分并关联事物。

    例如,我的A 版本的模板特化如下所示:

    template <typename T>
    struct A<T, 5> {
    };
    

    正如您所看到的,这与您建议的朋友前向声明语法奇怪地接近,并且可能很难判断您是否打算指定一个专门的版本。它需要将模板参数与模板参数进行匹配,而按照目前的方式,如果您没有模板参数,那么您并不是在谈论专业化。

    【讨论】:

    • 'template ' 行将定义相关的 S,我不明白你的意思。这就像我在课堂上的任何地方定义两个冲突的名字一样。不过,你对 1 的解释是非常合理的,谢谢。
    • @sbi,谢谢!我修好了它。 @rmn,我更新了答案以考虑您的评论。
    猜你喜欢
    • 1970-01-01
    • 2016-02-24
    • 2011-05-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-18
    • 2015-11-25
    • 1970-01-01
    相关资源
    最近更新 更多