Распаковка первого параметра из пакета параметров шаблона c

#c #templates #parameter-pack

#c #шаблоны #пакет параметров

Вопрос:

Я новичок в шаблонах, особенно с пакетом параметров, и мне интересно, смогу ли я получить первое значение из пакета.

Например, следующий код:

 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.. . может содержать различные типы (string, boolean и т.д.)

Комментарии:

1. Есть ли что-то, что мешает вам попробовать это самостоятельно и посмотреть, так ли это на самом деле?

Ответ №1:

Более простой в вашем случае, похоже, меняет вашу функцию на:

 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::stringamp; s, Args... args) {
    if (!Foo<T>(s, args...) {
        std::cerr << "Failed call Foo with "   s   "n";
    }
}
 

else <tuple> предоставляет несколько полезных инструментов:

 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";
    }
}
 

Ответ №2:

Вы можете использовать lambda для извлечения первого параметра:

 template<typename T, typename... Args>
bool register(Args... args) {
  if (!Foo<T>(args...)) {
    autoamp; first = [](autoamp; first, ...) -> autoamp; { 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:

Обычно я использую решение, описанное выше, просто добавляю явный дополнительный параметр шаблона для первого параметра. Если вы не можете этого сделать, это тоже работает :

 #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_tamp;amp;... 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;
}