一个C++涉及重要模板和友元声明的语法问题

发布于 2024-08-20 06:26:09 字数 860 浏览 8 评论 0原文

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

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

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

感谢您的任何帮助。

The following code should be self explanatory. I have two questions regarding the used syntax (which is the syntax that must be used). I'll be forever grateful if you could provide me with answers for these presented questions.

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

I have verified that indeed this is the only correct syntax (I'll be happy to find out I'm mistaken). My questions are more regarding the reasoning behind the syntax, as explained in the questions' body.

Thanks for any help.

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

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

发布评论

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

评论(3

徒留西风 2024-08-27 06:26:09

为什么语法不是...

为什么语法不能...

您希望我们说什么?无论谁决定了这个语法(主要是 Stroustrup 本人,据我所知)都认为他们的语法比你的更好。

我不知道哪一个更好或更容易记住——但我确实发现他们的比你的更有意义。当然,你可以自由地表达不同意见。

编辑:好的,亚历山大很好地回答了问题#2。关于 #1:

区别在于 A 命名一个 type,这是函数参数所期望的,而 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
};

所以与模板建立友好关系是一个例外(“通常的”friend声明声明了一个函数或类)并且确实需要不同的语法。

why isn't the syntax ...

Why can't the syntax be ...

What do you expect us to say? Whoever decided this syntax (mostly Stroustrup himself, AFAIK) thought their syntax better than yours.

Which one is nicer or easier to remember I wouldn't know - but I do find theirs making more sense than yours. You're free to disagree, of course.

Edit: OK, Alexander has nicely answered question #2. About #1:

The difference is that A<S> names a type, which is what is expected for a function argument, while A by itself is the name of a template, from which types are to be created, which makes sense if you want to befriend a template instead of a type:

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

You can befriend a specific template instance instead of the whole template, but for that the template must already be known by the compiler (i.e., declared) at the friend declaration:

template< typename T >
class foo;

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

So befriending a template is an exception (the "usual" friend declarations declares a function or class) and does need the differing syntax.

∞梦里开花 2024-08-27 06:26:09

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

Albeit I can't say why this syntax was choosen, I can just say that I would support both decisions made by the language designers - they make sense to me. In Question 2, you have not only one template, you have two nested templating levels. Why should the syntax to define a template member of a template class hide this fact? This way, it's just a re-combination of existing template syntax, while yours would require special rules to merge the template arguments for nested templates in one template<>.

北方。的韩爷 2024-08-27 06:26:09

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

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 ),您突然使编译器必须推断出 SJ 意味着模板参数,不应该从某个随机范围中获取。假设有人在与 struct A 相同的作用域级别引入了类型 S?声明 friend struct A 会引用哪个 S?编译器怎么知道?在外部作用域中引入名称以从根本上改变嵌套作用域中声明的含义是否合理?

如果您的意思是声明总共应为: template; friend struct A,那么为什么友元前向模板声明看起来与标准模板声明有什么不同呢?当您已经在 template 部分中提到模板变量的名称时,在模板名称后面包含模板变量的名称是多余的。

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

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

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

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

Suppose your nested template declaration were just a little more complicated:

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

Suddenly your suggestion doesn't seem so reasonable or obvious anymore. Which set of arguments goes first? Suppose you were using C++0x and had a variable argument list?

As for the friend declaration, by having the syntax you propose (friend struct <S, J>), you suddenly make the compiler have to deduce that S and J are meant as template arguments and should not be grabbed from some random scope. Suppose someone introduced a type S at the same scoping level as struct A? Which S would the declaration friend struct A<S,J> refer to? How would the compiler know? Is it reasonable to have the introduction of a name in an outer scope to radically change the meaning of a declaration in a nested scope?

And if you meant that the declaration should read, in total: template <typename S, int J> friend struct A<S, J>, then why should a friend forward template declaration look any different from a standard template declaration? It's redundant to include the names of the template variables after the name of the template when you already mention them in the template <typename S, int J> part.

I also think your suggested syntax would make figuring out what a template specialization is doing a lot harder because you'd have to look at more parts of the code and correlate things.

As an example, a template specialization of my version of A would look like this:

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

And as you can see, this is strangely close to your suggested friend forward declaration syntax, and it might be hard to tell whether or not you're intending to specify a specialized version or not. It would require matching up template arguments with template parameters whereas in the way it's currently done, if you have no template parameters you aren't talking about a specialization.

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