Ошибка вывода пакета параметров шаблона Variadi c - PullRequest
1 голос
/ 10 марта 2020

Я экспериментирую с метапрограммированием. Пока я пытался объединить variadic types с std::tuple, я столкнулся с проблемой.

#include <tuple>

template<typename... Args , typename... TupleArgs>
void f( Args&&... , const std::tuple<TupleArgs...>& )
{   }

template<typename... Args , typename... TupleArgs>
void f2( const std::tuple<TupleArgs...>& , Args&&... )
{   }

int main(){
    auto t = std::make_tuple( 1 , 2 , 2.0 , 3.0f );

    // f ( 1 , 2 , t ); // deduction/substition failed
    f2( t , 1 , 2 ); // Ok, no problem
} 

см. В Интернете

Я интуитивно ожидаю, что обе функции скомпилируются без ошибок , но, похоже, компилятор жалуется на это.

Может кто-нибудь объяснить, почему f дает ошибку удержания / замены, а f2 нет?

Есть ли обходной путь (я уверен, что есть)?

Компилятор: x86-x64 G CC 9.2 с -std = c ++ 17 опция

Ответы [ 2 ]

3 голосов
/ 10 марта 2020

f терпит неудачу, потому что компилятор не может определить, является ли передаваемый ему аргумент кортежа t частью списка Args&&... или является экземпляром const std::tuple<TupleArgs...>& (который в данном случае является одиночным кортежем) который имеет тип variadi c).

f2 Первый аргумент на самом деле является единственным типом (кортеж), за которым следует пакет параметров c variadi *1018*, поэтому любой параметр, который Вы передаете после того, как первый параметр явно принадлежит Args&&.... Обратите внимание, что я имею в виду параметры фактической функции, а не объявление шаблона. Прототипы функций - это то, что вызывает такое поведение.

Если вы хотите иметь два пакета параметров в списке параметров функции, то вы можете сделать несколько трюков, например поместить ОБА в кортежи или один в шаблоне. параметр шаблона (вложенные шаблоны).

Я включил два примера решения. Я изменил f для использования двух кортежей и создал новую функцию f3, которая использует параметр шаблона шаблона.

#include <tuple>

template<typename... Args, typename... TupleArgs>
void f(const std::tuple<Args...>&, const std::tuple<TupleArgs...>&)
{   }

template<typename... TArgs, template <typename...> class T, typename... TupleArgs>
void f3(T<TArgs...>&, const std::tuple<TupleArgs...>&)
{   }

template<typename... Args, typename... TupleArgs>
void f2(const std::tuple<TupleArgs...>&, Args&&...)
{   }

int main() {
    auto t = std::make_tuple(1, 2, 2.0, 3.0f);
    auto t2 = std::make_tuple(1, 2);

     f( t2 , t ); // FIXED
    f2(t, 1, 2); // Ok, no problem
    f3(t2, t);
}
1 голос
/ 10 марта 2020

Проблема с

template<typename... Args, typename... TupleArgs>
void f( Args&&... , const std::tuple<TupleArgs...>& );

в том, что Args&&... не выводится, как не последний параметр.

Возможное решение - предоставить шаблон:

f<int, int> ( 1 , 2 , t ); (тогда Args&&..., вероятно, должно быть Args...).

Другой обходной путь - иметь его в последнем параметре и использовать SFINAE, чтобы разрешить только кортеж в качестве последнего аргумента:

// Traits to detect std::tuple
template <typename> struct is_tuple : std::false_type{};
template <typename...Ts> struct is_tuple<std::tuple<Ts...>> : std::true_type{};

// Helper function to retrieve tuple and argument
template <typename Tuple, std::size_t...Is>
void f3_impl(Tuple&& tuple, std::index_sequence<Is...>)
{
    f2(std::get<sizeof...(Is)>(std::forward<Tuple>(tuple)),
       std::get<Is>(std::forward<Tuple>(tuple))...);
}

template<typename... Args>
std::enable_if_t<sizeof...(Args) != 0
             && (is_tuple<std::decay_t<Args>>::value, ...)> /* Only use LAST value */
f3( Args&&... args)
{
    f3_impl(std::forward_as_tuple(std::forward<Args>(args)...),
            std::make_index_sequence<sizeof...(Args) - 1>());
}

Демо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...