【问题标题】:Parameters after parameter pack in function [duplicate]函数中参数包后的参数[重复]
【发布时间】:2026-01-23 13:25:01
【问题描述】:

我能够在 SO 上找到 one question,它似乎在问与我相同或相似的问题,但没有答案 :-(

我想在参数包之后放置一个非模板参数。我对可变参数模板/参数包的 C++ 标准规范不太熟悉,但我的常识假设告诉我,传递给函数的最右边的参数将首先填充到放置参数中,然后将其余的填充到参数包。但是,我无法让我的测试代码在 g++ 或 clang++ 上运行。示例代码如下。

#include <vector>
#include <iostream>

int Subscribe(int channel, int callback)
{
    return channel;
}

// This one works fine...
template<typename... T>
std::vector<int> SubscribeMultiple1(int callback, T&&... channels)
{
    return {
        Subscribe(std::forward<T>(channels), std::move(callback))...
    };
}

// This one does not work; all I did was move `int callback` after the parameter pack.
template<typename... T>
std::vector<int> SubscribeMultiple2(T&&... channels, int callback)
{
    return {
        Subscribe(std::forward<T>(channels), std::move(callback))...
    };
}

int main()
{
    auto subs = SubscribeMultiple2(1, 2, 3);

    for (auto sub : subs)
    {
        std::cout << "Sub: " << sub << '\n';
    }
}

Live Sample

所以我的第一个问题是,为什么非模板参数在参数包后不起作用?我做错了什么还是语言禁止这样做?

其次,有什么方法可以得到我想要做的语法吗?我过度简化了我的示例,但在我的真实代码中,callback 参数实际上是std::function&lt;...&gt;。这个想法是我可以订阅一些“事件ID”,最后定义回调。最后有回调更好的可读性和样式。示例:

SubscribeMultiple(EventOne, EventTwo, EventThree, [] {
    // Implement callback code here when any of the above
    // three events are fired.
});

如果我必须在前面有回调,恕我直言,它的可读性较差。所以我愿意尝试任何解决方法来获得我想要的语法和结构。提前致谢。

【问题讨论】:

  • 我认为编译器无法确定参数包的结束位置,因为它的评估方式。如果我没记错的话,这家伙解释得很好:youtu.be/…
  • 谢谢@keith。任何文本版本?
  • cppcon 2016 的幻灯片都在官方 github 页面github.com/CppCon/CppCon2016 上。 2016 年有一个关于可变参数的演讲 - 也值得一看。
  • P.S.如果您首先想要可变参数,请将它们包装在一个类中!然后,您至少可以为额外的两个大括号执行 SubscribeMultiple2({blah, blah,...}, callback)。

标签: c++ variadic-templates


【解决方案1】:

我做错了什么还是语言禁止这样做?

只有当包是最后一个参数时才会扣除参数包。

[temp.deduct.type]/5.7:

未推断的上下文是:

  • [...]
  • 不出现在parameter-declaration-list末尾的函数参数包。

这是标准 C++ 的正常行为。

有什么办法可以得到我想要的语法吗?

使用第一种语法作为解决方法:

   template<typename... T>
   std::vector<int> SubscribeMultiple1(int callback, T&&... channels)

【讨论】: