igel
igel

Reputation: 557

C++ test for containers via SFINAE

In C++17, I'm trying to detect containers (maps) by checking for the presence of value_type (mapped_type). However, while it seems to work for unordered_set<int> it fails for unordered_set<int*> which I find weird. Can you tell me why and how to do it properly?

  template<class N, class T = int>
  struct is_container { static const bool value = false; };
  template<class N>
  struct is_container<N, typename N::value_type> { static const bool value = true; };
  template<class N>
  static constexpr bool is_container_v = is_container<remove_reference_t<N>>::value;


int main()
{
  cout << is_container_v<unordered_set<int>&> << '\n';
  cout << is_container_v<unordered_set<int*>&> << '\n';
}

output:

1
0

PS: I've seen this question which filters by presence of begin() but that doesn't help telling a map from set.

Upvotes: 0

Views: 116

Answers (1)

Jarod42
Jarod42

Reputation: 217850

Keeping your test, it should be

template<class N, class Enabler = void>
struct is_container { static const bool value = false; };

template<class N>
struct is_container<N, std::void_t<typename N::value_type>>
{ static const bool value = true; };

template<class N>
static constexpr bool is_container_v = is_container<remove_reference_t<N>>::value;

As, with your version

is_container_v<unordered_set<int*>&> is is_container<unordered_set<int*>> and with default: is_container<unordered_set<int*>, int>

whereas you specialize for is_container<unordered_set<int*>, int*>...

Upvotes: 3

Related Questions