Question

I was trying to make a program, which automatically detects the data type of input given by user. My approach :

int input(istream& i)
{
         int k;
         i>>k;
         return k;
}
float input(istream& i)
{
         float k;
         i>>k;
         return k;
}
void showval(int h){cout<<h;}
void showval(float h){cout<<h;}                 
int main()
{
         showval(input(cin));
         return 0;
}

As you can see, I used overloading of parameters and overloading of return type of two different functions, but at the same time. However, the program gives error as

"new declaration float input(istream& i) disambiguates the old declaration int input(istream& i)”.

I don’t understand, how this creates ambiguity. Is it because, the two different functions (showval and input) are dependent?

Also after going through few articles on overloading, what i realised is that in C++, methods can be overloaded only if they differ by parameters. However this link has a trick by which he was able to overload functions by return type. Is it possible to use the same trick in my program? Also, is there any way by which i can tell the compiler that the function input has parameter which is user dependent, and its data type may or may not differ. Does C++ forbid such possibilty?

Was it helpful?

Solution

Let's say that types such as int and float are specific, and types such as the proxy object shown in the linked question are generic. Our options are to be specific to begin with, in which case we just coast through the rest, or we give rise to a generic type and handle all the various specific types we may support.

The proxy object shown in the linked question is an example of a variant type, and boost::variant is a generic implementation of this. For example, boost::variant<int, float> allows us to hold either int or float.

My recommendation really depends what you want. Do you

  1. want to specify the type you expect to get from the user and throw on unexpectd input? (specific to begin with and coast) OR,
  2. want to give rise to a different type depending on what the user inputted and specify a set of types you can handle? (Give rise to a generic type and handle the various specific types)

Specifying the type you expect from the user

In this case we can simply make the function templated and we specify the type we expect through the template parameter.

The example shown is kept totally generic but you can restrain template parameters using various techniques. Check out my answer regarding this topic.

#include <iostream>

/* Read data of type T from an input stream. */
template <typename T>
T read(std::istream &strm) {
  T val;
  strm >> val;
  if (!strm) {
    throw /* something */;
  }  // if
  return val;
}

/* Print data of type T. */
template <typename T>
void print(const T &val) {
  std::cout << val;
}

int main() {
  print(read<int>(std::cin));
}

This will give rise to an int for input such as 1 and even for input such as 1., 1.0 and 1.2.

Handling different types you may get from the user

In this case we're actually lexing the input stream from the user. Our read function will give rise to a generic type, boost::variant<int, float>.

#include <iostream>

#include <boost/variant.hpp>

/* Naive implementation of a lexer. */
boost::variant<int, float> read(std::istream &strm) {
  std::string lexeme;
  strm >> lexeme;
  try {
    std::size_t idx;
    auto val = std::stoi(lexeme, &idx);
    if (idx == lexeme.size()) {  // Make sure we converted the entire lexeme.
      return val;
    }  // if
  } catch (const std::exception &) {
    // Do nothing. We'll try to lex it as float instead.
  }  // try
  std::size_t idx;
  auto val = std::stof(lexeme, &idx);
  if (idx == lexeme.size()) {  // Make sure we converted the entire lexeme.
    return val;
  }  // if
  throw /* something */;
}

/* Print the type and the value, to check that we have the correct type. */
void print(const boost::variant<int, float> &val) {
  class visitor : public boost::static_visitor<void> {
    public:
    void operator()(int that) const {
      std::cout << "int: " << that << std::endl;
    }
    void operator()(float that) const {
      std::cout << "float: " << that << std::endl;
    }
  };  // visitor
  boost::apply_visitor(visitor(), val);
}

int main() {
  print(read(std::cin)); 
}

This approach will give rise to int for input such as 1, and give rise to float for input such as 1., 1.0 as 1.2.

As you can see, we give rise to a generic type, boost::variant<int, float>, and handle the various specific types, int and float, in the visitor.

OTHER TIPS

The problem is that the compiler cannot possibly know which version of input to call. It is only within input that you actually attempt to extract from the stream, and only at that point can you know what the user has inputted. And even then, there's no reason the user can't enter 1.5 and then you extract into an int, or they enter 5 and you extract into a float.

Types are compile-time constructs. The compiler uses the type information to produce the program executable, so it must know what types are being used at compile time (way before the user inputs anything).

So no, you can't do this quite like this. You could extract a line from the input, parse it to determine whether it's a floating point value or an integer (does it have a .?), and then have a separate execution path for each case. However, instead I recommend deciding what the input that you expect from the user is (an int or a float?) and just extract that.

And also no, the trick with the proxy won't work for you. Firstly, as I mentioned, the format of the input is not known at compile time anyway. But secondly, in that code, the type that was required was known by the type of the variable being declared. In one line they did int v = ... and in the other they did double u = .... In your case, you're passing the result to showval which could take either an int or double and the compiler has no idea which.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top