【问题标题】:Why is this substitution of variadic template parameter failing ? (pack before fixed arguments)为什么这种可变参数模板参数的替换失败了? (在固定参数之前打包)
【发布时间】:2015-11-13 17:56:17
【问题描述】:

这是一个触发编译错误的最小示例:

#include <utility>
void foo(int, double, int)
{}

template <class... Args>
void post_forwarder(void(*fun)(Args..., int), Args&&... aArgs)
{
    fun(std::forward<Args>(aArgs)..., 5);
}

int main()
{
    post_forwarder(foo, 6, 6.1); // Compilation error on instantiation
    return 0;
}

我怀疑问题与可变参数模板参数在固定 int 参数之前的函数类型中扩展的事实有关,但如果是这种情况,我找不到很好的理由。

Clang 3.6报的错误是:

error: no matching function for call to 'post_forwarder'
note: candidate template ignored: failed template argument deduction

【问题讨论】:

  • 你能发布错误吗?这会很有帮助。
  • 顺便说一句,推断 Args&amp;&amp;... 转发到预期的函数指针 Args... 不是一个好计划。只要确保你知道这一点。
  • @Yakk 我必须承认我真的可以使用更多关于你提出的观点的细节:)
  • @adn 转发引用类型很少与您在完全不同的代码中用于表示变量的完全相同。您正在使用来自变量A... 的转发引用推导类型来匹配不是从这些变量生成的函数指针。想想转发rsference推导的4种情况,对应的函数指针一定是什么类型。如果这没有意义,请复习一下转发引用做了什么(这不是魔术),或者在除了最简单的上下文之外停止使用它们。

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


【解决方案1】:

这里的参数推导失败:

template <class... Args>
void post_forwarder(void(*fun)(Args..., int), Args&&... aArgs)
                           //  ^^^^^^^

对于一般规则,参数包必须在最后才能被演绎。通常的解决方案是将其包装在不可演绎的上下文中,这样甚至不会尝试演绎:

template <typename T>
struct identity {
    using type = T;
};

template <class... Args>
void post_forwarder(void(*fun)(typename identity<Args>::type..., int), Args&&... aArgs)
{
    fun(std::forward<Args>(aArgs)..., 5);
}

【讨论】:

  • 嗯,从技术上讲,第一个Args... 已经处于非推断上下文中。
  • @T.C.是的,但现在它是一个 super 非推断上下文。 [另外,我没有完整的解释]
  • stackoverflow.com/questions/26885239/… 。作为旁注,在这些情况下,我真的更喜欢identity 的别名,例如dont_deduce,所以即使我不了解机制,至少我知道其目的是什么。
  • @T.C.如果它是非推断上下文,那么它为什么会失败?
【解决方案2】:

这行得通:

template <class F, class... Args>
void post_forwarder(F f, Args&&... aArgs) {
    f(std::forward<Args>(aArgs)..., 5);
}

LIVE DEMO

【讨论】:

  • 它确实有效,但问题是尝试理解为什么建议的最小示例不起作用? (因为它是从一个更复杂的系统中提取的,您提出的替代方案无法替代预期的功能)。
  • @AdN 抱歉,我有一些重要的东西无法回复。这是一个不可演绎的上下文,这就是它失败的原因。但你已经有了答案。
【解决方案3】:

编辑:重写答案:

Args..., int 的形式不允许推导Args...

【讨论】:

  • 你确定吗? fun 签名中有一个明确的最后一个 int,我希望它将 Args... 扣除限制为前 2 个参数。
猜你喜欢
  • 2017-01-27
  • 1970-01-01
  • 2020-01-27
  • 2019-07-31
  • 2012-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多