【问题标题】:Get Last element of parameter pack in C++17 / C++20在 C++17/C++20 中获取参数包的最后一个元素
【发布时间】:2020-04-20 11:10:07
【问题描述】:

我想获取参数包的最后一个元素。我使用以下代码GodBolt

template<typename... Args>
auto last(Args&&... args){
   const auto& last = (args, ...);
   return last;
}

但现在我收到警告

逗号运算符的左操作数无效

但这正是我想要实现的...有没有办法说清楚。 一般来说,我喜欢收到未使用值的警告,所以我不想禁用所有这些值(-Wno-unused-value)。

此外,我可以使用递归模板来实现,但折叠表达式在这里似乎更好。

【问题讨论】:

  • 请忽略按值返回/右值引用 ...
  • 有一个预处理器指令用于暂时禁用程序一部分的警告。
  • Pre c++17 解决方案:godbolt.org/z/b-nfp3

标签: c++ c++17 c++20


【解决方案1】:

在任何函数调用中包装 args 都会消除警告。

您可以专门为此目的创建一个身份函数,但您不妨使用std::forward 并获得适当的转发作为奖励。

template<typename... Args>
decltype(auto) last(Args&&... args){
   return (std::forward<Args>(args), ...);
}

【讨论】:

  • std::forward 不是最佳选择,因为它被标记为 nodiscard... 在 clang 中,您会收到以下警告:> 忽略使用“nodiscard”属性声明的函数的返回值
  • @BerndBaumanns 无法在 gcc.godbolt.org 上使用 libstdc++ 和 libc++ 进行复制。但无论如何,如果出于某种原因,forward 对你来说是 nodiscard,我建议为它编写一个自定义替换。
  • 它与 gcc 一起工作正常,但 clang / msvc 抱怨......你的第一个解决方案似乎很好
  • 我在下面为其他人添加了来自 HolyBlackCat 的原始答案
【解决方案2】:

制作一个元组并获取最后一个元素:

template<typename... Args>
auto last(Args&&... args)
{
    return std::get<sizeof...(Args)-1>(std::forward_as_tuple(args...));
}

测试:

int main()
{
    auto&& last_element = last(1, 1.0, true);
    static_assert(std::is_same_v<bool, std::remove_cvref_t<decltype(last_element)>>);
}

Demo

C++11 Friendly Demo

【讨论】:

  • 这个解决方案也不错。
【解决方案3】:

根据 HolyBlackCat 的建议,删除此警告的最简单方法是使用这样的“身份/虚拟函数”:

template<typename T>
constexpr inline decltype(auto) identityFkt(T&& t)
{
    return std::forward<T>(t);
}

可以这样使用:

const auto& last = (identityFkt(std::forward<AParamPack>(aParamPack)), ...);

它导致相同的程序集(检查@godbolt)-没有开销(使用-O3)。

谢谢你:@HolyBlackCat

【讨论】:

    【解决方案4】:

    您可以使用其他实现(效率较低,但编译器应该能够消除此处的低效率)

    template <class T>
    decltype(auto) last(T && ... t) { return t; }
    
    template <class ... TT,class T>
    decltype(auto) last(T &&,TT && ... tt) { return last( std::forward<TT>(tt)... ); }
    

    【讨论】:

    • 你这里有几个无关的...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-19
    • 2015-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多