is there a way to write a metafunction is_container?

Hi,

I have a metafunction is_vector but how can I write one for all container types?
This is my current code:

1
2
3
4
5
6
7
8
9
10
11
template<typename T>
struct is_vector
{
	constexpr static bool value = false;
};

template<typename T>
struct is_vector<std::vector<T>>
{
	constexpr static bool value = true;
};



of course I can write one for each type of container class but I am looking for something less manual...


regards,

Juan
do you seek
string s = typeid(a).name()
if(something about s) ... ?
??
Last edited on
Heh, I wrote this for my magic for loop before, and have found it useful in odd places.
Here you go :O)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iterator>
#include <type_traits>
#include <utility>

//-----------------------------------------------------------------------------------------------
// is_iterable <T> ::value
//-----------------------------------------------------------------------------------------------
// The basis for this code was found at
// https://stackoverflow.com/a/29634934/2706707
//
namespace is_iterable_internal
{
  using std::begin;
  using std::end;

  template <typename T>
  struct is_iterable
  {
    template <typename U>
    static constexpr auto is_iterable_impl( int ) 
      -> decltype(
           begin( std::declval <U&> () ) != end( std::declval <U&> () ),   // begin/end and operator !=
           void(),                                                         // Handle evil operator ,
           ++std::declval <decltype( begin( std::declval <U&> () ) )&> (), // operator ++
           void( *begin( std::declval <U&> () ) ),                         // operator*
           std::true_type {}
         )
    { return std::true_type {}; }
  
    template <typename U>
    static constexpr std::false_type is_iterable_impl(...)
    { return std::false_type {}; }
  
    typedef decltype( is_iterable_impl <T> ( 0 ) ) type;
  };
}


template <typename T>
struct is_iterable
{
  #if __cplusplus < 201402L
    enum :           bool { value = is_iterable_internal::is_iterable <T> ::type::value };
  #else
    static constexpr bool   value = is_iterable_internal::is_iterable <T> ::type::value;
  #endif
};

49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <iostream>
#include <type_traits>
#include <utility>
#include <vector>

template <typename Container>
typename std::enable_if <is_iterable <Container> ::value, void> ::type
do_something( const Container & xs )
{
  for (auto x : xs)
    std::cout << x << "\n";
}

int main()
{
  std::vector <int> v = { 2, 3, 5, 7 };
  do_something( v );

  int n = 42;
  do_something( n );

  auto p = std::make_pair( 3.14159265, -7 );
  do_something( p );
}
C:\Users\Michael\foo> cl /EHsc /W4 /Ox /std:c++17 a.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.21.27702.2 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

a.cpp
a.cpp(68): error C2672: 'do_something': no matching overloaded function found
a.cpp(68): error C2893: Failed to specialize function template 'std::enable_if<is_iterable<T>::value,void>::type do_something(const Container &)'
a.cpp(68): note: With the following template arguments:
a.cpp(68): note: 'Container=int'
a.cpp(71): error C2672: 'do_something': no matching overloaded function found
a.cpp(71): error C2893: Failed to specialize function template 'std::enable_if<is_iterable<T>::value,void>::type do_something(const Container &)'
a.cpp(71): note: With the following template arguments:
a.cpp(71): note: 'Container=std::pair<double,int>'
~/baz% clang++ -Wall -Wextra -pedantic-errors -O3 -std=c++17 a.cpp
a.cpp:68:3: error: no matching function for call to 'do_something'
  do_something( n );
  ^~~~~~~~~~~~
a.cpp:56:1: note: candidate template ignored: requirement 'is_iterable<int>::value' was not satisfied
      [with Container = int]
do_something( const Container & xs )
^
a.cpp:71:3: error: no matching function for call to 'do_something'
  do_something( p );
  ^~~~~~~~~~~~
a.cpp:56:1: note: candidate template ignored: requirement 'is_iterable<std::pair<double, int> >::value' was not
      satisfied [with Container = std::pair<double, int>]
do_something( const Container & xs )
^
2 errors generated.

As you can see, it compiles fine for the vector (or any other iterable standard container), but not for anything else: it complains for the int and the std::pair.

Enjoy!
> how can I write one for all container types?

It would be a very elaborate construction;
we would need to check for all the standard container requirements, and there are very many:
https://eel.is/c++draft/container.reqmts

Here is an attempt: https://github.com/MiSo1289/more_concepts/blob/master/include/more_concepts/base_containers.hpp#L18

Probably better to just check for the concepts required for a specific set of operations of interest.
For example, as in:
1
2
template< std::ranges::bidirectional_range R > requires std::permutable< std::ranges::iterator_t<R>>
    constexpr std::ranges::borrowed_iterator_t<R> std::ranges::reverse( R&& r );

https://en.cppreference.com/w/cpp/algorithm/ranges/reverse
Last edited on
thanks!!
Topic archived. No new replies allowed.