vendredi 30 avril 2021

determine if function argument is a sequence in C++?

On my way to write a simple traversal through auto generated data structures I was wondering why type_traits do not provide sth. like std::is_sequence.

I am using this make_array :

template <typename... T>
  constexpr auto make_array(T&&... values) 
  -> std::array< typename std::decay< typename std::common_type<T...>::type>::type, sizeof...(T)> {
    return {std::forward<T>(values)...};
  }

to create structures like this:

auto z = make_array(
    make_array('h','e','l','l','o'),
    make_array('w','o','r','l','d')
 );

The elements could be of different types and dimensions as well. Later I'd like to support more complex uses such as func(1,2,MyClass(3),4.0,make_array(5,6,7),std::make_tuple(8.0,"9.1011",12)) ,or func({13,14,15}), but that I consider as a 2nd step ... ;)

(Whether or not such ideas will ever make it into my project I don't yet know. I am just curious ...)

My approach is to write two overloaded, templated functions func:

template<typename T>
typename std::enable_if<!is_sequence<T>::value, void>::type
func(T& t) {
  std::cout << "\n\tfunc(t) => " << t << ' ';
}


template<typename SeqT> 
typename std::enable_if<is_sequence<SeqT>::value, void>::type
func(SeqT&  s) {
  std::cout << "\nfunc(SeqT& s)...";
  for(auto iter=std::begin(s);iter!=std::end(s);++iter) func(*iter);
  std::cout << "\n...func(SeqT& s)...";
}

And with the help of

template <typename T>
class is_sequence {
private:
    typedef char YesType[1];
    typedef char NoType[2];

    template <typename C> static YesType& test(decltype(std::begin(C{})));
    template <typename C> static NoType& test(...);

public:
    enum { value = sizeof(test<T>(0)) == sizeof(YesType) };
};

(idea stolen from https://www.bfilipek.com/2016/02/notes-on-c-sfinae.html)

it seams to work:

func(z);

prints

func(SeqT& s)...
func(SeqT& s)...
        func(t) => h 
        func(t) => e 
        func(t) => l 
        func(t) => l 
        func(t) => o 
...func(SeqT& s)
func(SeqT& s)...
        func(t) => w 
        func(t) => o 
        func(t) => r 
        func(t) => l 
        func(t) => d 
...func(SeqT& s)
...func(SeqT& s)

Here come my questions:

(1) I don't think my need and general approach is soo special. But the wise C++ guys obviously did not see the need to put sth. like ```is_sequence''' into the standard. What am I missing then ?

(2) What other suggestions do you have for me ?

Aucun commentaire:

Enregistrer un commentaire