0

I'm trying to write a function that takes as an input argument a string, three output arguments that can be of varying types (at least that's the idea) and a char that is a delimiter.

The input string is delimited by the specified char and the function assigns each char-terminated field to each of the output arguments in order (at the moment it takes care of input strings such as "a;bb;ccc" and is limited to three output arguments only but that's not the problem).

For example with an input such as 10;200;3000 I'd get 10, 200 and 3000 for the first, second and third output arguments respectively

The output arguments need to be of either string or integer types, but due to my limited knowledge of C++ (and in particular generic programming) I'm having trouble writing a generic function that doesn't care about that.

I have the following code:

template <typename T>
void parse_string (std::string &input, T &out1, T &out2, T &out3, const char delimiter)
{
    while (out3 == "")
    {
        std::string temp = input.substr(0, input.find(delimiter));
        input = input.substr(input.find(delimiter) +1);

        if (out1 == "") { out1 = temp;}
        else if (out2 == "") { out2 = temp;}
        else { out3 = temp;}
    }
}

and it works fine for strings but obviously not for integers.

I suspect I'm going wrong in the bits where I check if the argument is empty (among other parts I don't know about).

Could you please help me improve it?

Also, I would welcome any ideas on improving the logic itself (perhaps I'd need to go with the variadic templates to make the number of arguments flexible, but I'd have to check with our technical lead if C++11 standards are okay).

Ideally I'd like to avoid the situation where I have the exact same function twice but with a different signature for each of the types (one for strings and one for ints).

Many thanks in advance!

2 Answers 2

3

I would go with splitting the string into strings (as you do) and then converting them to required type.

You can use boost::lexical_cast for that, or std::stringstream

template <typename To, typename From>
To cast(const From &arg)
{
    std::stringstream s;
    s << arg;
    To res;
    s >> res;

    if (s.fail())
    {
        //throw some_exception();
    }

    return res;
}

In any case if you have boost available it is the right way to go

Sign up to request clarification or add additional context in comments.

1 Comment

lexical_cast is something like this with more error checking. Main thing is that you can return res uninitialized here, if the value of arg doesn't parse when written and then read.
2
#include <algorithm>
#include <string>
#include <sstream>

template <typename T1, typename T2, typename T3>
void parse_string(const std::string& input, T1& out1, T2& out2,
                  T3& out3, char delimeter)
{
  std::istringstream is1(input);

  std::string field;
  for (int i = 0; std::getline(is1, field, delimeter) && i < 3; ++i)
  {
    std::istringstream is2(field);
    switch (i)
    {
    case 0: is2 >> out1; break;
    case 1: is2 >> out2; break;
    case 2: is2 >> out3; break;
    }

    if (is2.fail()) 
    {
      // do something about invalid type conversion?
    }
  }

  // up to you to decide what to do if the string has too
  // many or too few fields
}

lexical_cast would be safer tho!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.