如何修复 gcc 警告“友元声明声明非模板函数”

发布于 2025-01-09 04:36:53 字数 2245 浏览 4 评论 0原文

所以我这里有一些使用 gcc、clang 和 msvc 进行编译的代码:

#include <cstdio>
#include <type_traits>

struct c_class;

template <class T> struct holder { friend auto adl_lookup(holder<T>); };

template <class C, class T> struct lookup {
  friend auto adl_lookup(holder<T>) { return holder<C>{}; }
};

struct cpp_class : lookup<cpp_class, c_class *> {
  cpp_class() {}
};

int main() {
  static_assert(std::is_same<holder<cpp_class>,
                             decltype(adl_lookup(holder<c_class *>{}))>{},
                "Failed");
}

adl_lookup 是在 lookup 类而不是 holder 中定义的原因类的作用是,当您继承 CRTP 类时,您可以从 c_classcpp_class 进行“反向”查找 lookup。所以友元函数不能移动到holder类中。

但是,在 gcc 上,我收到有关非模板友元函数的警告:

<source>:9:37: warning: friend declaration 'auto adl_lookup(holder<T>)' declares a non-template function [-Wnon-template-friend]
    9 |     friend auto adl_lookup(holder<T>);
      |                                     ^
<source>:9:37: note: (if this is not what you intended, make sure the function template has already been declared and add '<>' after the function name here)

如果我尝试通过前向声明函数然后使用 <> 来修复此问题,则它不会使用 gcc 或 msvc 进行编译(尽管它是否使用 clang 进行编译):

#include <cstdio>
#include <type_traits>

struct c_class;

template <class T> struct holder;

template <class T> auto adl_lookup(const holder<T> &);

template <class T> struct holder {};

template <class C, class T> struct lookup {
  friend auto adl_lookup<>(const holder<T> &) { return holder<C>{}; }
};

struct cpp_class : lookup<cpp_class, c_class *> {
  cpp_class() {}
};

int main() {
  static_assert(std::is_same<holder<cpp_class>,
                             decltype(adl_lookup(holder<c_class *>{}))>{},
                "Failed");
}

我在这里使用符合标准的 C++(在两个片段中)吗?是否有理由担心 gcc 关于非模板朋友的警告,或者这只是我可以安全忽略的误报?

So I have some code here that compiles with gcc, clang, and msvc:

#include <cstdio>
#include <type_traits>

struct c_class;

template <class T> struct holder { friend auto adl_lookup(holder<T>); };

template <class C, class T> struct lookup {
  friend auto adl_lookup(holder<T>) { return holder<C>{}; }
};

struct cpp_class : lookup<cpp_class, c_class *> {
  cpp_class() {}
};

int main() {
  static_assert(std::is_same<holder<cpp_class>,
                             decltype(adl_lookup(holder<c_class *>{}))>{},
                "Failed");
}

The reason adl_lookup is defined in the lookup class instead of the holder class is so that you can do a "reverse" lookup from c_class to cpp_class when you inherit from the CRTP class lookup<cpp_class, c_class *>. So the friend function can't be moved to the holder class.

However, on gcc I get a warning about non template friend function:

<source>:9:37: warning: friend declaration 'auto adl_lookup(holder<T>)' declares a non-template function [-Wnon-template-friend]
    9 |     friend auto adl_lookup(holder<T>);
      |                                     ^
<source>:9:37: note: (if this is not what you intended, make sure the function template has already been declared and add '<>' after the function name here)

If I try to fix this by forward declaring the function and then using <>, it doesnt compile with gcc or msvc(although it does compile with clang):

#include <cstdio>
#include <type_traits>

struct c_class;

template <class T> struct holder;

template <class T> auto adl_lookup(const holder<T> &);

template <class T> struct holder {};

template <class C, class T> struct lookup {
  friend auto adl_lookup<>(const holder<T> &) { return holder<C>{}; }
};

struct cpp_class : lookup<cpp_class, c_class *> {
  cpp_class() {}
};

int main() {
  static_assert(std::is_same<holder<cpp_class>,
                             decltype(adl_lookup(holder<c_class *>{}))>{},
                "Failed");
}

Am I using standard-compliant C++ here(in both snippets)? Is there a reason to be concerned about gcc's warning about non-template friend or is it just a false positive that I can safely ignore?

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

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

发布评论

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

评论(2

素罗衫 2025-01-16 04:36:53

第二个片段的格式不正确,因为 friend 声明不能是模板特化的定义。用于接受此问题的开放式 clang 错误报告位于此处

第一个对我来说似乎有效。

GCC 的警告很烦人,因为将非模板函数定义为友元正是您想要在此处执行的操作。不幸的是,我认为没有任何方法可以在代码中表明这确实是您想要做的,但您可以使用 -Wno-non-template-friend 禁用警告。根据 文档 它就在那里由于历史原因,为了识别 ISO-C++ 之前的兼容性问题,其中语法具有不同的含义。

您应该意识到,使用这种友元注入来启用有状态元编程的能力可能被认为是该语言的意外功能,并且可能(我不知道)在将来的某个时候受到限制,请参阅 这个问题

The second snippet is ill-formed, because a friend declaration cannot be a definition of a template specialization. An open clang bug report for accepting this is here.

The first one seems valid to me.

The warning by GCC is annoying, because defining a non-template function as friend is what you want to do here. Unfortunately I don't think there is any way to indicate in code that this is really what you want to do, but you can disable the warning with -Wno-non-template-friend. According to the documentation it is there for historical reasons, to identify pre-ISO-C++ compatibility issues where the syntax had a different meaning.

You should be aware that the ability to use friend injections of this kind to enable stateful metaprogramming may be considered unintended feature of the language and could maybe (I don't know) be restricted at some point in the future, see this question.

如果没有你 2025-01-16 04:36:53

这是一个常见的错误,因为使用 if (var = foo()) 而不是 if (var == foo()),即使代码是合法的。

而添加额外的父级允许“通知”编译器意图是 =/== 情况下所期望的。

if ((var = foo()))

没有任何技巧语法可以告诉您它实际上是您想要使用的非模板函数。

仍然有传统的 #pragma 方法来禁用给定编译器的特定区域中的警告(请参阅如何禁用几行代码的 gcc 警告

It is a common mistake, as using if (var = foo()) instead if (var == foo()) even if the code are legal.

Whereas adding extra parents allow to "inform" compiler of intent is the one expected in the =/== case.

if ((var = foo()))

There are no trick syntax to tell that it is really a non-template function that you want to use.

There are still traditional #pragma way to disable warning in specific region for given compiler (see how-to-disable-gcc-warnings-for-a-few-lines-of-code)

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