【问题标题】:Unpacking first parameter from template parameter pack c++从模板参数包c ++中解包第一个参数
【发布时间】:2022-01-08 02:24:23
【问题描述】:

我是模板新手,特别是参数包,我想知道是否可以从包中获取第一个值。

例如下面的代码:

template <typename T, typename... Args>
bool register(Args... args) {
    if (!Foo<T>(args..) {
        assert(std::is_same_v<std::string, args...[0]>);
        std::cerr << "Failed call Foo with " + args...[0] + "\n";
    }
}

如何真正获得args... 中的第一个值?

值得注意的是args..。可以包含不同的类型(字符串、布尔值等)

【问题讨论】:

  • 是否有什么阻碍您自己尝试并查看是否是这种情况?

标签: c++ templates parameter-pack


【解决方案1】:

我通常使用上述解决方案,只需为第一个参数添加一个显式的额外模板参数。如果你不能这样做,这也可以:

#include <type_traits>

namespace details
{
    template<typename type_t, typename... args_t>
    struct deduce_first
    {
        using type = type_t;
    };
}

template<typename... args_t>
using first_t = typename details::deduce_first<args_t...>::type;

template<typename... args_t>
bool register_f(args_t&&... args)
{
    static_assert(std::is_same_v<first_t<args_t...>, bool>, "first argument should have type bool");
    return true;
}

int main()
{
    register_f(true, 1.0);
    // register_f(1.0); <== does indeed not complie

    return 0;
}

【讨论】:

    【解决方案2】:

    可以使用 lambda 提取第一个参数:

    template<typename T, typename... Args>
    bool register(Args... args) {
      if (!Foo<T>(args...)) {
        auto& first = [](auto& first, ...) -> auto& { return first; }(args...);
        static_assert(std::is_same_v<std::string,
                                     std::remove_reference_t<decltype(first)>>);
        std::cerr << "Failed call Foo with " + first + "\n";
      }
    }
    

    【讨论】:

      【解决方案3】:

      在您的情况下更简单似乎将您的功能更改为:

      template <typename T, typename Arg, typename... Args>
      bool register(Arg arg, Args... args) {
          if (!Foo<T>(arg, args...) {
              assert(std::is_same_v<std::string, Arg>);
              std::cerr << "Failed call Foo with " + arg + "\n";
          }
      }
      

      从断言中,甚至

      template <typename T, typename... Args>
      bool register(const std::string& s, Args... args) {
          if (!Foo<T>(s, args...) {
              std::cerr << "Failed call Foo with " + s + "\n";
          }
      }
      

      else &lt;tuple&gt; 提供了一些有用的工具:

      template <typename T, typename Arg, typename... Args>
      bool register(Args... args) {
          if (!Foo<T>(args...) {
              assert(std::is_same_v<std::string,
                                    std::tuple_element_t<0, std::tuple<Args...>>);
              std::cerr << "Failed call Foo with "
                  + std::get<0>(std::tie(args...)) + "\n";
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-17
        • 1970-01-01
        • 1970-01-01
        • 2014-09-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多