0

There are many ways to convert strings to numbers in C++: stoi, stod, stof, etc. Just like how std::invoke is a nice way to call any callable, I am looking for a method that converts string value to a generic numeric value.

For instance, instead of something like this:

int x = std::stoi("5");
long y = std::stol("5555555555");

Something like this:

int x = num_convert("55");
long y = num_convert("5555555555");

Is there any standard functionality for what I am trying to do?

TwistedBlizzard
  • 931
  • 2
  • 9
  • Are you looking for a `std::hash`? – Sam Varshavchik Aug 27 '22 at 23:58
  • 2
    I don't believe there is any way to do this, as a function can only return one type, and you cannot overload functions only changing the return type. I would recommend making different names for the functions, for example `num_convert_long` and `num_convert_int`. – cs1349459 Aug 28 '22 at 00:05
  • @cs1349459 Then they might as well be using the functions that are already available in the Standard Library. – sweenish Aug 28 '22 at 02:12

3 Answers3

2

What you want is not (easily) viable in C++. The return value of a function is defined by the function name and the arguments it is given (ie: the result of overload resolution). Your hypothetical num_convert("55") and num_convert("5555555555") expressions both take the same argument type. Therefore, they must (usually) call the same function which returns the same value.

Thus, the simplest way to achieve what you want would be for such a function to return a proxy object that stores the argument it is given. The proxy would have conversion operators (operator int, operator long, etc) which would perform the actual conversion.

Of course, this means that auto i = num_convert("55") will not actually do the conversion. If the function was given a temporary, i would contain a reference to that temporary. Which means that any uses of i would be broken, since they would reference a temporary whose lifetime has ended.

The standard doesn't have a function like this.

It would be better to write the type explicitly into the call as a template parameter and then use auto deduction instead of using a proxy: auto i = num_convert<int>("55");. The standard has no such function either. But really, there's not much difference between num_convert<int> and stoi, so just use it.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
2

This can be considered as a generic conversion:

#include<sstream>

int main() {
  int x;
  std::stringstream("55") >> x;

  long y;
  std::stringstream("5555555555") >> y;
}

A function can return only a single type, thus long y = num_convert("5555555555") with a regular function is impossible.

One more hack, help the function to deduce the returned type with the unused parameter:

#include <string>

template<typename T>
T num_convert(const char* s, const T&) {
  return static_cast<T>(std::stoll(s));
}

int main() {
  int x = num_convert("55", x);
  long y = num_convert("5555555555", y);
}
273K
  • 29,503
  • 10
  • 41
  • 64
  • This is undefined behavior. See [here](https://stackoverflow.com/questions/73643920/calling-function-with-variabl-that-is-being-initialized/73643982#73643982). – Jason Sep 08 '22 at 05:10
  • Please show this in the Standard. If you show it, I can easy update the code for using const references. – 273K Sep 08 '22 at 05:31
  • You can look at all the dupes linked [here](https://stackoverflow.com/questions/73643920/calling-function-with-variable-that-is-being-initialized/73643982#73643982). If you think that this is not UB then those dupes won't apply and that question can be reopened. Additionally, this is explained in any beginner c++ book. – Jason Sep 08 '22 at 05:37
  • Neither of the dupes refer the C++ Standard. I have only found this UB in C. – 273K Sep 08 '22 at 05:38
  • You can confirm that this is UB. See [demo](https://wandbox.org/permlink/zych05m1K23th7P4). – Jason Sep 08 '22 at 05:42
  • Ok, changing the answer. But the example warns about another issue "is not usable in a constant expression" – 273K Sep 08 '22 at 05:48
1

If you have boost then just use

auto x = boost::lexical_cast<short>("5"s);
auto y = boost::lexical_cast<long>("5555555555"s);

Demo on Godbolt

You can also roll out your own lexical_cast like what boost did, if you don't want to use it

For more information read Boost.LexicalCast

phuclv
  • 37,963
  • 15
  • 156
  • 475