【问题标题】:C++ variadic templates of different input type using c++11使用c ++ 11的不同输入类型的C ++可变参数模板
【发布时间】:2018-10-16 19:28:39
【问题描述】:

最近我对现代 c++ 进行了研究。我看到了一个关于 c++11/c++14 可变参数模板的video [in 49:00]。如果你想用可变参数模板计算不同类型(如intdouble)的元组之和,使用c++11,视频建议了一个解决方案:

struct Sum
{
    template<typename T>
    static T sum(T n)
    {
        return n;
    }

    template<typename T, typename... Args>
    static auto sum(T n, Args... rest) -> decltype(n+sum(rest...))
    {
        return n + sum(rest...);
    }
}
auto x = Sum::sum(1, 2.5, 3);

auto 无法推断出c++11 中的返回类型,因此您必须使用decltype 声明返回类型。但是有些编译器构建失败,有些编译器构建成功。link

虽然使用auto to deduce return type没有问题,但我的问题是:

  1. c++11 标准是否涵盖了这个问题?如果不是,编译器是否通过自己的实现来处理问题?
  2. 为什么最新版gcc 8.1编译失败,而gcc 4/5/6/7编译成功? gcc 是否存在兼容性问题?

顺便说一下,编译错误信息是:

test.cc:20:16: 错误:没有匹配的函数调用 'sum'

 double x = Sum::sum(1, 2.5, 3);

test.cc:12:17:注意:候选模板被忽略:替换失败 [with T = int, Args = ]:使用未声明的标识符“sum”

 static auto sum(T n, Args... rest) -> decltype(n + sum(rest...))

test.cc:6:14:注意:候选函数模板不可行:需要 单个参数“n”,但提供了 3 个参数

static T sum(T n)

生成 1 个错误。

【问题讨论】:

  • 这在我看来像是一个编译器错误。似乎编译器试图在推导的返回类型中重用 sum 的相同实例化。
  • 这使用 'struct Sum` 作为命名空间。我会将其更改为 namespace Sum 并删除 static's。
  • @HenriMenke - 不是错误。功能。

标签: c++ c++11 variadic-templates


【解决方案1】:

这里的尾随返回类型中的函数名查找,

template<typename T, typename... Args>
static auto sum(T n, Args... rest) -> decltype(n+sum(rest...))

在此 sum 声明之前的上下文中完成,并通过 ADL(依赖于参数的查找)。

由于在调用相关类型时通过 ADL 看不到此模板,因此编译失败是正确的。

较旧的 gcc 编译器可能除了使用它们应该使用的上下文之外还使用了对象上下文。这是一个合理的错误。

您可以轻松解决此问题:

struct Sum {
private:
  template<typename T>
  friend T summer(Sum, T n) {
    return n;
  }
  template<typename T, typename... Args>
  friend auto summer(Sum, T n, Args... rest) -> decltype(n+summer(Sum{},rest...)) {
    return n + summer(Sum{},rest...);
  }
public:
  template<class...Args>
  auto sum(Args...args)->decltype(summer(Sum{}, args...)){
    return summer(Sum{}, args... );
  }
};

这里我们在一些私人朋友中强制 ADL。这允许 Summer 的重载在其尾随返回类型中“看到自己”。

【讨论】:

  • 干得好。您可能想添加一些通用参考 &amp;&amp; 的东西。
  • “夏天的负担” - 这不是海明威的小说吗?
  • 干得好,雅克。我尝试了这个解决方案,gcc 8.1 有效,但 clang 不起作用。见link。所以这些差异的关键是function-name lookup,不是吗?
  • 为什么这个修复有效?换句话说,为什么添加虚拟标签和结交朋友有助于强制 ADL?
  • @0x4996 标准?在两个上下文中查找函数名称。一是在函数定义处冻结;实例化时的 ADL。朋友不是强迫 ADL 的因素,朋友让我保密。
猜你喜欢
  • 2011-12-14
  • 1970-01-01
  • 1970-01-01
  • 2012-07-10
  • 1970-01-01
  • 2016-06-01
  • 2015-11-10
相关资源
最近更新 更多