c++ - C++11 中递归元函数的延迟返回类型解析

标签 c++ templates c++11 template-meta-programming

我正在尝试用 C++11 编写一个简单的序列生成器,它接受一些开始和结束索引并在编译时生成一个整数序列。由于 integer_sequence 在 C++14 之前不可用,我使用自定义可变参数模板容器来存储整数序列:

template <int...>
struct IntSequence {};

现在我想调用sequence_generator返回给我一个 IntSequence 容器的函数,该容器以我请求的整数范围为模板。

auto t = sequence_generator<3, 5>();

这里我期望 t成为IntSequence<3,4,5> .我以递归方式展开序列生成器并使用 enable_if 停止递归:

template <int S, int E, int... Seq>
auto sequence_generator() -> enable_if_t<(S <= E), IntSequence<Seq...>> {
// Pack S into the variadic sequence and increment to S+1.  
return sequence_generator<S + 1, E, S, Seq...>();
}

template <int S, int E, int... Seq>
auto sequence_generator() -> enable_if_t<!(S <= E), IntSequence<Seq...>> {
  return IntSequence<Seq...>{};
}

但是我的 enable_if 的构造函数不正确,因为我使用当前递归步骤中可用的可变参数包声明返回类型。相反,我希望编译器展开整个递归链并选择基本情况的返回类型(即 IntSequence<3,4,5> 。我不知道如何实现。

最佳答案

首先,让我们从返回类型推导中拆分 SFINAE

template <int S, int E, int... Seq, std::enable_if_t<(S <= E), int>* =nullptr>
auto sequence_generator() -> ???

接下来,函数体应该只是return {};:

template <int S, int E, int... Seq, std::enable_if_t<(S <= E),int>* =nullptr>
auto sequence_generator() -> ???
{
  return {};
}

因为为什么要重复我们自己。

在我们合成返回类型时可见的函数是在该函数模板之前声明的函数,以及通过 ADL 找到的任何函数。

这个集合不包括我们自己。

因此我们将创建一个 details 命名空间,并按如下方式强制 ADL:

namespace details {
  struct helper {};

  template <int S, int E, int... Seq, std::enable_if_t<(S <= E), int>* =nullptr>
  auto sequence_generator(helper, IntSequence<S,E,Seq...>)
  -> ???
  {
    return {};
  }
  ???
}
template<int S, int E, int...Seq>
auto sequence_generator()
-> decltype( sequence_generator(details::helper{}, IntSequence<S,E,Seq...>{}) )
{
  return {};
}

这有趣地消除了为 details::sequence_generator 实际拥有主体的需要。

namespace details {
  struct helper {};

  template <int S, int E, int... Seq, std::enable_if_t<(S <= E), int>* =nullptr>
  auto sequence_generator(helper, IntSequence<S,E,Seq...>)
  -> ???

  template <int S, int E, int... Seq, std::enable_if_t<(S > E), int>* =nullptr>
  auto sequence_generator(helper, IntSequence<S,E,Seq...>)
  -> ???
}
template<int S, int E, int...Seq>
auto sequence_generator()
-> decltype( sequence_generator<S,E,Seq...>(helper::details{}) )
{
  return {};
}

我们现在必须实现这两个功能。

  template <int S, int E, int... Seq, std::enable_if_t<(S <= E), int>* =nullptr>
  auto sequence_generator(helper, IntSequence<S,E,Seq...>)
  -> decltype( sequence_generator(helper{}, IntSequence<S + 1, E, S, Seq...>{}) );

  template <int S, int E, int... Seq, std::enable_if_t<(S > E), int>* =nullptr>
  auto sequence_generator(helper, IntSequence<S,E,Seq...>)
  -> IntSequence<Seq...>;

and done (live example).

请注意,我将所有内容都作为参数传递,从中推导出模板参数。这允许 adl 正常工作。

另一种方法是在没有辅助函数的情况下直接构造类型;我假设您出于自己的原因使用函数来构造类型。基于函数的模板元编程有很多优点;查看 boost hana 以了解您可以走多远。也有缺点,例如您必须通过 ADL 循环才能递归返回类型。

关于c++ - C++11 中递归元函数的延迟返回类型解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36632985/

相关文章:

c++ - 为什么在未评估的操作数内进行包扩展会导致最后一个元素?

c++ - qt 音频输出示例未构建——缺少生成器类声明

c++ - 从嵌套的 QStandardItemModel 中的特定列中提取所有数据

c++ - STL 容器及其元素的常量性——何时使用常量?

c++ - 为什么编译器不针对同一翻译单元中的 ODR 违规发出警告

c# - 在自定义 ITemplate 中查找控件

c++11 - QTextDocument::print 中的段错误

java - 密码破解

c++ - 如何使用 CDT 配置 Eclipse?

c++ - 我可以将 `extern template` 放入头文件中吗?