Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
238 views
in Technique[技术] by (71.8m points)

c++ - Failed resolution of variadic parameter types with post-positioned std::index_sequence

Assume a sequence of variadic parameter types is to be generated according to a index sequence, i.e, given a tuple

using Tuple = std::tuple<int, float, bool>;

and a function signature as following:

template <std::size_t ...Is>
void func(std::index_sequence<Is...>, std::tuple_element_t<Is, Tuple>...) {}

a invocation like func(std::make_index_sequence<2>(), 2, 1.0) would compile without problem.

However, if we were to compute the size of std::index_sequence according to another type, and therefore place std::index_sequence at the end of parameter list with a default argument, just like this:

template <typename T, std::size_t ...Is>
void func(T, std::tuple_element_t<Is, Tuple>..., std::index_sequence<Is...> = std::make_index_sequence<some_computation_v<T>>()) {}

The compilation of g++ and clang++ would succeed if and only if the size of std::index_sequence is 0, that is, for following signature:

template <std::size_t... Is>
void func(std::tuple_element_t<Is, Tuple>..., std::index_sequence<Is...> = std::make_index_sequence<2>()) {}

func(2, 1.0) or func(2, 1.0, std::make_index_sequence<2>()) would result in error:

main.cpp:34:6: note:   template argument deduction/substitution failed:
main.cpp:43:16: note:   mismatched types ‘std::integer_sequence<long unsigned int, _Idx ...>’ and ‘int’
     func(2, 1.0);

This prevents me from restricting the types of variadic template with a key type T, by mapping T to a tuple of parameter types and expand it using std::index_sequence.

Is there any way to resolve this error or to meet the needs mentioned above?

question from:https://stackoverflow.com/questions/65870951/failed-resolution-of-variadic-parameter-types-with-post-positioned-stdindex-se

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Write a "is prefix of types" trait. Use it in a requires clause.

template<class T0>
struct is_tuple_prefix_helper{
    template<class T1>
    static std::false_type test(T1 const&);
};
template<template<class...>class Z, class...T0s>
struct is_tuple_prefix_helper<Z<T0s...>>{
    template<class T1>
    static std::false_type test(T1 const&);
    template<class...T1s>
    static std::true_type test(Z<T0s...,T1s...> const&);
};

template<class T0, class T1>
constexpr bool is_tuple_prefix_v=decltype( is_tuple_prefix_helper<T0>::test(std::declval<T1>()) )::value;

Then

using tup=std::tuple<int,char,double>

template<class...Ts> requires( is_tuple_prefix_v<std::tuple<Ts...>, tup> )
void restricted_func(Ts const&...);

should work.

The problem you have is that you are asking to invert a compile time type mapping. C++ will not invert most compile time type mappings for you; doing so in general is HALT-hard, so C++ does not try. It will do basic pattern matching, that is all.

This allows you to write a Turing-complete inversion or test, but you have to write it.

This is based. An earlier version of C++ would instead use SFINAE and other less elegant machinery to do the same thing. In :

template<class...Ts,
  std::enable_if_t< is_tuple_prefix_v<std::tuple<Ts...>, tup>, bool > =true
>
void restricted_func(Ts const&...);

How that exactly works is crazy black magic, honestly. There is a reason they added requires in .


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...