代码之家  ›  专栏  ›  技术社区  ›  rmn

一个包含非平凡模板和朋友声明的C++语法问题

  •  3
  • rmn  · 技术社区  · 15 年前

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

    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);
    }
    

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

    谢谢你的帮助。

    3 回复  |  直到 15 年前
        1
  •  5
  •   Community CDub    7 年前

    为什么语法不…

    为什么语法不能是…

    你希望我们说什么?不管是谁决定了这个语法(主要是stroustrup本人,afaik),他们都认为自己的语法比你的好。

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

    编辑: 好啊, Alexander has nicely answered question #2 . 关于α1:

    区别在于 A<S> 名字A 类型 ,这是函数参数的预期值,而 A 它本身就是一个 模板 ,从中创建类型,如果希望与 模板 而不是类型:

    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
    

    可以 成为特定模板的朋友 实例 而不是整个模板,但为此,编译器必须已经在 friend 宣言:

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

    所以和一个 模板 是一个例外(通常 朋友 声明声明声明了一个函数或类),并且需要不同的语法。

        2
  •  5
  •   Alexander Gessler    15 年前

    尽管我不能说 为什么 这个语法是choosen,我可以说我支持语言设计者做出的两个决定——它们对我来说是有意义的。在问题2中,您不仅有一个模板,还有两个嵌套的模板化级别。为什么定义模板类的模板成员的语法应该隐藏这个事实?这样,它只是对现有模板语法的重新组合,而您的模板语法需要特殊的规则将嵌套模板的模板参数合并到一个模板中。 template<> .

        3
  •  2
  •   Omnifarious    15 年前

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

    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声明,使用您建议的语法( friend struct <S, J> ,你突然让编译器推断出 S J 是指作为模板参数,不应从某些随机范围中获取。假设有人介绍了一种类型 S struct A 是吗?哪个 S 声明会不会 friend struct A<S,J> 是指?编译器如何知道?在外部作用域中引入名称是否合理,以彻底改变嵌套作用域中声明的含义?

    如果你的意思是声明应该读,总共: template <typename S, int J> friend struct A<S, J> 那么,为什么friend forward模板声明看起来与标准模板声明有什么不同呢?当您已经在 template <typename S, int J> 部分。

    我还认为您建议的语法将使您更难弄清楚模板专门化在做什么,因为您必须查看代码的更多部分并将它们关联起来。

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

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

    正如您所看到的,这与您建议的friend forward声明语法非常接近,可能很难判断您是否打算指定一个专门的版本。它需要将模板参数与模板参数进行匹配,而按照目前的方式,如果没有模板参数,则不会讨论专门化。