0

In its current state the program validates input for data types: int and string.

//valid score range between 0 and 100
bool validScore(int value) 
{
  if(value < 0 || value > 100)
      return false;
  return true;
}
//valid name composed of letters
bool validName(string word)
{
  for(int i = 0; i < word.length(); i++)
  {
    if(!isalpha(word[i]) )
        return false;
  }
  return true;
}

Input is obtained through two functions for each data type: get_int() and get_word().

The validation functions are optional parameters for cases where int range is unspecified and names may contain any character.

bool get_int(const string&, int&, bool(*validScore)(int) = 0);
bool get_word(const string&, string&, bool(*validWord)(const string) = 0);

// bool get_int(const string& prompt, int&n, (*validScore)(int)) 
bool get_word(const string& prompt, string&word, bool(*validWord)(const string) )
{
  while(1)
  {
    string line;
    cout << prompt;

    if(!getline(cin, line) 
      break;

    istringstream iss(line);

    if(iss >> word) // iss >> n
    {
      // validScore == 0 || validScore(n)
      if(validWord == 0 || validWord(word)) 
        return true;
    }
  }
  return false;
}

I am wondering, if possible, how to correctly declare a function template that could streamline the process when validation is required.

template<typename T> bool get_item(const string&, T&, ???);

Would overloading the function template get_item with the different validation functions be a potential solution?

andres
  • 301
  • 6
  • 21
  • seems like you just want a template function `valid(const T &)`, that only has specializations for types it supports? – dwcanillas Jun 08 '15 at 21:40

2 Answers2

4

If you really like function pointers, then

template<typename T> bool get_item(const string&, T&, bool (*)(const T&) = nullptr);

or

template<typename T> bool get_item(const string&, T&, bool (*)(T) = nullptr);

to match the existing signatures of your valid* functions (note that this would incur a copy).

You can also make it completely generic:

template<typename T, typename F> bool get_item(const string&, T&, F);

To handle the case where no validation is required, a separate overload can be used:

template<typename T> bool get_item(const string &s, T &t){
    return get_item(s, t, [](const T&){return true;});
}
T.C.
  • 133,968
  • 17
  • 288
  • 421
  • You should alter to "If you really like function pointer syntax." The generic version still uses function pointers (if those are passed). In the cases in which no function pointer is passed, the original version wouldn't work either (apart from the minuscule portion of cases in which a functor provides a corresponding conversion operator). – Columbo Jun 08 '15 at 22:04
  • I sometimes use `[](T const&)->std::true_type{return{};}` as an extra hint to the optimizer. Not sure it makes a difference. – Yakk - Adam Nevraumont Jun 09 '15 at 12:28
0

Take the validator as a template type:

template<class T>
bool get_item(const string& prompt, T& item);

template<class T, class Validator>
bool get_item(const string& prompt, T& item, Validator validator);

There is an implied template policy here that a Validator is callable with a T and returns a bool. Since concepts it not yet in C++, you might just comment the template policy.

David
  • 27,652
  • 18
  • 89
  • 138