可变参数模板递归返回类型推导编译错误

2023-11-25

为什么下面的代码不能编译?

template <typename T>
T sum(T t){
    return t;
}

template <typename T, typename ...U>
auto sum(T t, U... u) -> decltype(t + sum(u...)) {
    return t + sum(u...);
}

int main() {
    sum(1, 1.5, 2);
}

编译错误:

error: no matching function for call to ‘sum(int, double, int)’
 sum(1, 1.5, 2);

实现此功能的良好解决方法是什么?


在这里,我们将工作转发给辅助类型:

namespace details {
  template<class...Ts>
  struct sum_t {};

  template<class T>
  struct sum_t<T> {
    T operator()(T t)const{ return std::forward<T>(t); }
  };

  template<class T, class...Ts>
  struct sum_t<T,Ts...> {
    auto operator()(T t, Ts...ts)const
    -> decltype( std::declval<T>() + sum_t<Ts...>{}(std::declval<Ts>()...) )
    {
      return std::forward<T>(t) + sum_t<Ts...>{}(std::forward<Ts>(ts)...);
    }
  };
}

template<class...Ts>
auto sum(Ts...ts)
-> decltype( details::sum_t<Ts...>{}(std::declval<Ts>()...) )
// -> std::result_of_t<details::sum_t<Ts...>(Ts...)>
// above line is C++14 and cleaner version of previous line
{
  return details::sum_t<Ts...>{}(std::forward<Ts>(ts)...);
}

基本问题是模板函数在计算自己的返回类型时无法看到自己-> decltype clause.

有一些解决方法。上面的代码应该可以工作,因为模板类可以在其自己的主体中看到其部分特化的其他特化。另一种方法是使用 Koenig 查找 (ADL) 推迟对其递归调用的搜索,直到实例化点,在那里它可以找到自己。我发现第二种方法更令人困惑。

如果我要自己写sum对于生产,我可以选择采用我期望它返回的类型,如果它这样做,它将接受零长度和(创建默认实例),但如果我传递 1 或,则不要求该类型是默认可构造的更多的争论。但我喜欢过度设计的通用代码:

template<class R0=void,class...Ts,class R=std::conditional_t<
  !std::is_same<R0,void>{},
  R0,
  std::result_of_t<details::sum_t<Ts...>(Ts...)>
>>
R sum(Ts...ts)
{
  return details::sum_t<R, Ts...>{}(std::forward<Ts>(ts)...);
}

我修改的地方sum_t将返回类型作为第一个参数:

namespace details {
  template<class R,class...Ts>
  struct sum_t {
    R operator()()const{ return {}; }
  };

  template<class R, class T>
  struct sum_t<R, T> {
    using R0 = std::conditional_t<!std::is_same<R,void>{},R,T>;
    R0 operator()(T t)const{ return std::forward<T>(t); }
  };

  template<class R, class T, class...Ts>
  struct sum_t<R, T,Ts...> {
    using R0 = std::conditional_t<
      !std::is_same<R,void>{},
      R,
      decltype( std::declval<T>() + sum_t<void,Ts...>{}(std::declval<Ts>()...) )
    >;
    R0 operator()(T t, Ts...ts)const
    {
      return std::forward<T>(t) + sum_t<void,Ts...>{}(std::forward<Ts>(ts)...);
    }
  };
}

这让我希望能够写“计算总和,但将每个子总和转换为R在继续之前”或类似的内容。

在 C++1z 中,您需要使用折叠表达式。能够设定R仍然有用,就像您正在添加表达式模板一样,它可能仅在当前作用域结束之前作为表达式模板有效。

要在 C++14 中解决此问题,您可能必须使用连续传递样式R返回值。

然后我们可以将返回类型推导折叠到游戏中以允许

Matrix m = sum( many_matrices... );

在 Eigen 工作(例如)。

当你第一次开始编写通用代码时,你必须问自己“我们想要进入兔子洞多深?”

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

可变参数模板递归返回类型推导编译错误 的相关文章

随机推荐

  • 无法在此事件处理程序中执行操作

    我正在尝试从 DataGridView 中删除一行我使用两种类型的指令 A VouchersDGV Rows Clear B If Not DGV Rows RowIndex IsNewRow Then DGV Rows RemoveAt
  • Matlab 中的高效分类

    我有一张尺寸为 RGB 的图像uint8 576 720 3 我想将每个像素分类为一组颜色 我已经使用rgb2lab从RGB空间到LAB空间 然后删除L层 所以现在是double 576 720 2 由AB组成 现在 我想将其分类为我在另一
  • 总线错误排查

    我正在尝试反转字符串 这是我尝试过的代码 include
  • 编写 C++ 版本的代数游戏 24

    我正在尝试编写一个像游戏 24 一样工作的 C 程序 对于那些不知道如何玩的人 基本上你会尝试通过 四个代数运算符找到 4 个数字总计为 24 的任何方法 和括号 举个例子 假设有人输入 2 3 1 5 2 3 5 1 24 由于括号位置的
  • ADB 安装失败并显示 INSTALL_FAILED_TEST_ONLY

    我在将 apk 安装到我的设备时遇到问题 adb install lt apk gt 使用上述命令将返回以下内容 5413 KB s 99747 bytes in 0 017s pkg data local tmp AppClient Te
  • SQL 的扩展占位符,例如id 在哪里 (??)

    赏金更新 已经从马克那里得到了很好的答案 将 改编为 如下 然而 除了 DBIx 之外 我仍在寻找类似的方案 我只是想兼容anything 我需要有关我为参数化 SQL 语句中的 扩展 占位符选择的语法的建议 因为构建一些构造 IN 子句
  • 带弹性盒的计算器键盘布局

    我正在用 Flexbox 构建一个计算器 我想要其中一个键的高度是两倍 另一个键的宽度是两倍 我用谷歌搜索了很多 但找不到这两个案例 对于两倍高度的键 我发现的唯一答案是flex direction as column 但在这种情况下 我将
  • iPython 笔记本避免在函数内打印

    我想阻止某个函数在 iPython 笔记本中打印 在标准 python 中 可以防止打印问题中回答的某些代码行 防止函数在 Python 的批处理控制台中打印然而 此方法在 iPython Notebook 中不起作用 在内核重新启动之前会
  • 您如何在协作、版本控制的环境中处理 Oracle 软件包? [关闭]

    Closed 这个问题是基于意见的 目前不接受答案 我在 Oracle 的多开发人员环境中工作 有一个大包 我们有DEV gt TST gt PRD的促销模式 目前 所有包编辑都是直接在 TOAD 中进行 然后编译到 DEV 包中 我们遇到
  • 使用 Bash 重定向到多个文件时重定向不明确

    echo gt home jem rep 0 1 3 logs SystemOut log bash home jem rep 0 1 3 logs SystemOut log ambiguous redirect 我可以一次重定向到多个文
  • 如何根据特殊条件进行分组

    目前 当我发出此 SQL 时 它会获取不同的用户名 我有一些不同的用户名 它们代表组 例如GRP BSN 我想将所有其他用户名 恰好是数字 分组到一个组中 例如GRP OTHERS select username count from ho
  • 连接到 SoftHSM java

    Code String pkcs11cfg pkcs11 cfg Provider p new SunPKCS11 pkcs11cfg Security addProvider p KeyStore ks KeyStore getInsta
  • 如何在 Angular cli 6.0.1 中创建 Angular 5 项目

    My 角度 cli 版本是 6 0 1 and node版本是8 11 1 如何创建或添加 Angular 5 的新项目 如果我使用ng 新的 项目名称 然后该项目正在下载角6 我也偶然发现了这个场景 这是我的解决方案 不幸的是 我们受到
  • 找出 Windows 的安装语言为

    我遇到一个问题 用户设置的区域设置 德语 与安装的语言 Windows 英语 不同 有没有办法发现安装的 Windows 语言与用户设置的区域设置 我应该注意的问题是我正在创建共享 并且根据区域设置设置权限 因此如果用户将区域设置设置为德语
  • LFSR 实现中的高效位调整

    虽然我有一个很好的 LSFR C 实现 但我想我会在 Haskell 中尝试同样的方法 只是看看它是如何进行的 到目前为止 我的想法比 C 实现慢两个数量级 这就引出了一个问题 如何提高性能 显然 位调整操作是瓶颈 分析器也证实了这一点 这
  • 如何在 Node Js 应用程序的多个实例之间同步对象

    Node JS 应用程序中是否有任何对象可以锁定 是否有多个应用程序实例可用 某些功能不应并发运行 如果实例 A 功能完成 它应该解锁该对象 密钥或某些标识符 并且应用程序的 B 实例应该检查其解锁是否应该运行某些功能 任何对象或密钥都可以
  • 通过 BinaryReader 将字节数组解压缩为字符串会产生空字符串

    我正在尝试解压缩字节数组并使用二进制读取器将其转换为字符串 当执行以下代码时 inStream 位置从 0 更改为数组的长度 但 str 始终是空字符串 BinaryReader br null string str String Empt
  • JavaScript 方括号函数调用

    当我浏览 jQuery 源代码时 我遇到了这一行 jQuery this state show hide 相比之下有什么优势吗 state jQuery this show jQuery this hide 独立示例 var object
  • Google App Engine 和 Google Compute Engine 有什么区别?

    我想知道 App Engine 与 Compute Engine 之间有什么区别 谁能向我解释其中的区别吗 应用引擎是一个平台即服务 这意味着您只需部署代码 平台就会为您完成其他所有事情 例如 如果您的应用程序非常成功 App Engine
  • 可变参数模板递归返回类型推导编译错误

    为什么下面的代码不能编译 template