Clang 无法在 std::function 实例化中扩展参数包

2023-12-28

编译的代码片段std=c++17作为唯一的编译器标志...

  • ...使用 GCC 9.1 成功编译。Godbolt https://godbolt.org/z/QKJomx
  • ...使用 Clang 8.0.0 发出编译器错误(代码片段下方的错误)。Godbolt https://godbolt.org/z/S7tB5K

问题:这是 Clang 编译器中的错误,还是 GCC 接受此代码的错误,还是有其他原因?

#include <functional>
#include <tuple>

template <typename... Ts>
struct Foo
{
    template <typename T>
    using Int = int;

    // Function that accepts as many 'int' as there are template parameters
    using Function = std::function< void(Int<Ts>...) >;

    // Tuple of as many 'int' as there are template parameters
    using Tuple = std::tuple< Int<Ts>... >;

    auto bar(Function f)
    {
        std::apply(f, Tuple{}); // Error with Clang 8.0.0
    }
};

int main()
{
    auto foo = Foo<char, bool, double>{};
    foo.bar([](int, int, int){});
}

令我感到奇怪的是,Clang 的错误表明它已成功别名Tuple as std::tuple<int, int, int>但它错误地别名Function就这样std::function<void(int)>,只有一个而不是三个参数。

In file included from <source>:2:
In file included from /opt/compiler-explorer/gcc-8.3.0/lib/gcc/x86_64-linux-gnu/8.3.0/../../../../include/c++/8.3.0/functional:54:
/opt/compiler-explorer/gcc-8.3.0/lib/gcc/x86_64-linux-gnu/8.3.0/../../../../include/c++/8.3.0/tuple:1678:14: error: no matching function for call to '__invoke'
      return std::__invoke(std::forward<_Fn>(__f),
             ^~~~~~~~~~~~~
/opt/compiler-explorer/gcc-8.3.0/lib/gcc/x86_64-linux-gnu/8.3.0/../../../../include/c++/8.3.0/tuple:1687:19: note: in instantiation of function template specialization 'std::__apply_impl<std::function<void (int)> &, std::tuple<int, int, int>, 0, 1, 2>' requested here
      return std::__apply_impl(std::forward<_Fn>(__f),
                  ^
<source>:19:14: note: in instantiation of function template specialization 'std::apply<std::function<void (int)> &, std::tuple<int, int, int> >' requested here
        std::apply(f, Tuple{}); // Error
             ^
<source>:26:9: note: in instantiation of member function 'Foo<char, bool, double>::bar' requested here
    foo.bar([](int, int, int){});

额外的研究

正如评论中的其他用户已经指出的那样,Int模板别名取决于类型T修复问题:

template <typename T>
using Int = std::conditional_t<true, int, T>;

我还发现了其他一些事情,只是参考Function从外部输入也可以使其按预期/期望工作:

int main()
{
    auto f = Foo<char, bool, double>::Function{};
    f = [](int, int, int){};
}

TL;DR:这是一个 clang bug,但标准中也存在一个 bug。

首先要注意,在 C++ 中,模板分两步处理:

  1. 不存在的构造依赖的模板上的参数是在定义封闭模板时构建的。
  2. 依赖的构造是在实例化封闭模板时构建的。

现在看来 clang 对待std::function< void(Int<Ts>...) >作为非依赖类型,推理如下:

  1. Int<Ts>是非依赖类型(正确)。
  2. 因此,包扩展包含Int<Ts> (i.e. Int<Ts>...)也是一个非依赖的“类型”(?)。
  3. 因为所有组件void(Int<Ts>...)是非依赖的,它是非依赖类型(显然不正确)。
  4. 因为名字std::function是非依赖的并且模板参数void(Int<Ts>...)是一种非依赖非包扩展类型,std::function< void(Int<Ts>...) >是非依赖类型。

(请注意,“非包扩展”检查使其与Tuple case.)

因此,当Foo已定义,类型名称Function被视为命名非依赖类型,并立即构建,并且不考虑包扩展(在实例化期间发生)。因此,所有使用Function被“脱糖”类型取代std::function< void(int) >.

此外,clang 还有一个概念依赖于实例化,这意味着该构造是不依赖的,但它仍然以某种方式涉及模板参数(例如,该构造仅对某些参数有效)。std::function< void(Int<Ts>...) >被视为依赖于实例化的类型,因此当模板被实例化时,clang仍然执行替换using Function = std::function< void(Int<Ts>...) >。因此,Function获取正确的类型,但这不会传播到使用Function在定义中Foo.


现在这是标准中的错误。

类型是否依赖定义在[温度相关类型] http://eel.is/c++draft/temp.dep.type#9:

一个类型是依赖的,如果它是

  • 模板参数,
  • 未知专业的成员,
  • 作为当前实例化的依赖成员的嵌套类或枚举,
  • 一个 cv 限定类型,其中 cv 不限定类型是从属的,
  • 由任何依赖类型构造的复合类型,
  • 其元素类型是相关的或其边界(如果有)是值相关的数组类型,
  • 其异常规范与值相关的函数类型,
  • 表示为简单模板 ID其中模板名称是模板参数,或者任何模板参数是依赖项 类型或依赖于类型或值的表达式或者是 包扩展[ 注意:这包括一个注入类名 没有使用类模板模板参数列表。 — 尾注 ],或
  • 表示为decltype(expression),其中表达式取决于类型。

请注意,它并没有说参数列表包含包扩展的函数类型是依赖类型,只是说“从任何依赖类型构造的复合类型”和“异常规范依赖于值的函数类型”是依赖的。两者在这里都没有帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Clang 无法在 std::function 实例化中扩展参数包 的相关文章

  • 为什么libc++的shared_ptr实现使用完整内存屏障而不是宽松内存屏障?

    在boost的实现中shared ptr 它用放松内存排序以增加其引用计数 https github com boostorg smart ptr blob master include boost smart ptr detail sp
  • 使用post方法将多个参数发送到asp.net core 3 mvc操作

    使用 http post 方法向 asp net mvc core 3 操作发送具有多个参数的 ajax 请求时存在问题 参数不绑定 在 dot net 框架 asp net web api 中存在类似的限制 但在 asp net mvc
  • 显示异常时的自定义错误消息:从客户端检测到潜在危险的 Request.Form 值

    我在我的 Web 应用程序中使用 ASP NET 的登录控件 当发生此异常时 我想在标签上显示一种有趣的错误类型System Web HttpRequestValidationException A potentially dangerou
  • 如何使用recv()检测客户端是否仍然连接(并且没有挂起)?

    我写了一个多客户端服务器程序C on SuSE Linux 企业服务器 12 3 x86 64 我为每个客户端使用一个线程来接收数据 我的问题是 我使用一个终端来运行服务器 并使用其他几个终端来运行服务器telnet到我的服务器 作为客户端
  • 从多个类访问串行端口

    我正在尝试使用串行端口在 arduino 和 C 程序之间进行通信 我对 C 编程有点陌生 该程序有多种用户控制形式 每一个都需要访问串口来发送数据 我需要做的就是从每个类的主窗体中写入串行端口 我了解如何设置和写入串行端口 这是我的 Fo
  • IronPython:没有名为 json 的模块

    我安装了 IronPython 我的 python 文件如下所示 import sys print sys version import json 运行它的代码 var p Python CreateEngine var scope p C
  • 如何识别 WPF 文本框中的 ValidationError 工具提示位置

    我添加了一个箭头来指示工具提示中的文本框 当文本框远离屏幕边缘时 这非常有效 但是当它靠近屏幕边缘时 工具提示位置发生变化 箭头显示在左侧 Here is the Image Correct as expected since TextBo
  • C 语言中 =+(等于加)是什么意思?

    我碰到 与标准相反 今天在一些 C 代码中 我不太确定这里发生了什么 我在文档中也找不到它 In ancientC 版本 相当于 它的残余物与最早的恐龙骨头一起被发现 例如 B 引入了广义赋值运算符 使用x y to add y to x
  • 如何将“外部模板”与由同一类中的模板化成员使用的嵌套类一起使用?

    首先 一些背景信息 我尝试以 Herb Sutter 在他的解决方案中介绍的方式使用 Pimpl 习语 得到了 101 http herbsutter com gotw 101 这在头文件中看起来像这样 include pimpl h h
  • Qt 创建布局并动态添加小部件到布局

    我正在尝试在 MainWindow 类中动态创建布局 我有四个框架 它们是用网格布局对象放置的 每个框架都包含一个自定义的 ClockWidget 我希望 ClockWidget 对象在调整主窗口大小时相应地调整大小 因此我需要将它们添加到
  • 如何在c#中的内部类中访问外部类的变量[重复]

    这个问题在这里已经有答案了 我有两个类 我需要声明两个类共有的变量 如果是嵌套类 我需要访问内部类中的外部类变量 请给我一个更好的方法来在 C 中做到这一点 示例代码 Class A int a Class B Need to access
  • 当我“绘制”线条时,如何将点平均分配到 LineRenderer 的宽度曲线?

    我正在使用线条渲染器创建一个 绘图 应用程序 现在我尝试使用线条渲染器上的宽度曲线启用笔压 问题在于 AnimationCurve 的 时间 值 水平轴 从 0 标准化为 1 因此我不能在每次添加位置时都在其末尾添加一个值 除非有一个我不知
  • 获取 2 个数据集 c# 中的差异

    我正在编写一个简短的算法 它必须比较两个数据集 以便可以进一步处理两者之间的差异 我尝试通过合并这两个数据集并将结果更改放入新的数据集来实现此目标 我的方法如下所示 private DataSet ComputateDiff DataSet
  • 如何一步步遍历目录树?

    我发现了很多关于遍历目录树的示例 但我需要一些不同的东西 我需要一个带有某种方法的类 每次调用都会从目录返回一个文件 并逐渐遍历目录树 请问我该怎么做 我正在使用函数 FindFirstFile FindNextFile 和 FindClo
  • 耐用功能是否适合大量活动?

    我有一个场景 需要计算 500k 活动 都是小算盘 由于限制 我只能同时计算 30 个 想象一下下面的简单示例 FunctionName Crawl public static async Task
  • 使用 C# 从 DateTime 获取日期

    愚蠢的问题 给定日期时间中的日期 我知道它是星期二 例如我如何知道它的 tue 2 和 mon 1 等 Thanks 您正在寻找星期几 http msdn microsoft com en us library system datetim
  • 双精度类型二维多维数组的 pinvoke 编组作为 c# 和 c++ 之间的输入和输出

    我有以下我正在尝试解决的双物质类型的 2d 多维数组的 c 和 c pinvoke 编组 我已经查看了以下热门内容以获得我目前拥有的内容使用双精度数组进行 P Invoke 在 C 和 C 之间编组数据 https stackoverflo
  • 用于 C# XNA 的 Javascript(或类似)游戏脚本

    最近我准备用 XNA C 开发另一个游戏 上次我在 XNA C 中开发游戏时 遇到了必须向游戏中添加地图和可自定义数据的问题 每次我想添加新内容或更改游戏角色的某些值或其他内容时 我都必须重建整个游戏或其他内容 这可能需要相当长的时间 有没
  • 使用 Crypto++ 获取 ECDSA 签名

    我必须使用 Crypto 在变量中获取 ECDSA 签名 我在启动 SignMessage 后尝试获取它 但签名为空 我怎样才能得到它 你看过 Crypto wiki 吗 上面有很多东西椭圆曲线数字签名算法 http www cryptop
  • 是否可以在 C# 中强制接口实现为虚拟?

    我今天遇到了一个问题 试图重写尚未声明为虚拟的接口方法的实现 在这种情况下 我无法更改接口或基本实现 而必须尝试其他方法 但我想知道是否有一种方法可以强制类使用虚拟方法实现接口 Example interface IBuilder

随机推荐