2

I am trying to build a templated struct that will only take containers for T. I found this post that showed how to determine whether the passed in value is a container or not. So I decided to go ahead and try to use that for my program as I do not want the user to create a struct of integers, floats, or doubles.

Here is code that I have written:

template<typename T> 
struct is_container : std::integral_constant<bool, has_const_iterator<T>::value && has_begin_end<T>::beg_value && has_begin_end<T>::end_value> { };

template<typename T, typename Enable = void>
struct Cont;

template <typename T>
struct Cont<T, typename std::enable_if<is_container<T>::value>>
{
  Cont(const std::string &n) : name(n) {}
  std::string name;
};

However, when I try to write to main:

int main()
{
  Cont<std::vector<int>> myContainer("Vector");
}

I get a compiler error: Cont<std::vector<int> > myContainer has initializer but incomplete type. I'm kind of stuck on where to go with this, because if I remove the std::enable_if from the template parameter, it compiles just fine. Which leads me to believe that I am doing something wrong with std::enable_if or I am missing something rather simple.

What I am trying to achieve is the following:

int main()
{
  Cont<std::vector<int>> myContainer("Vector"); //happily compiles
  Cont<int> badContainer("Bad"); // will not compile
}

How can I achieve this?

max66
  • 65,235
  • 10
  • 71
  • 111
Sailanarmo
  • 1,139
  • 15
  • 41

1 Answers1

3

Which leads me to believe that I am doing something wrong with std::enable_if or I am missing something rather simple.

Exactly.

You have forgotten a ::type

template <typename T>  // add this ---------------------------vvvvvv
struct Cont<T, typename std::enable_if<is_container<T>::value>::type>
{
  Cont(const std::string &n) : name(n) {}
  std::string name;
};

Starting from C++14, you can also use std::enable_if_t (so you can remove the ::type and the preceding typename)

template <typename T>
struct Cont<T, std::enable_if_t<is_container<T>::value>>
{
  Cont(const std::string &n) : name(n) {}
  std::string name;
};
max66
  • 65,235
  • 10
  • 71
  • 111
  • Thank you, I did not know I needed `type` at the end. However, I decided to go with the `std::enable_if_t` option since it looks a lot cleaner. – Sailanarmo Mar 31 '19 at 21:23