1

I would like to work with istringstream within a function and I want the istringstream to be initialized by a string passed by value. Can I avoid the explicit istringstream iss_input(string_input); in the function body?

void f(istringstream command){
}

int main(){
    f( string("create_customer 1 Ben Finegold") );
}

The above demonstrates what I want to achieve, but it does not work. The problem I am solving is command parsing.

Community
  • 1
  • 1
Slazer
  • 4,750
  • 7
  • 33
  • 60
  • 1
    So you want the parameter of the function `f(...)` to be use directly to construct a local `istringstream` object in function `f`. Is that what you are asking? – Lucien Nov 29 '15 at 01:41
  • I don't understand what you get from this and why you would do that. If this is about recursive calls, why not overload `f`? – s.bandara Nov 29 '15 at 01:45
  • `istringstream`'s constructor from `string` is explicit, so no, you can't have an implicit conversion. Besides, `istringstream` is not copyable, you cannot accept it by value. Just take a string. – Igor Tandetnik Nov 29 '15 at 01:58
  • @s.bandara Because `f()` will be inside `map> commands;` and will be invoked like `commands[command](arguments)`. If I just overloaded `f()`, I would need a long long ifelse like this `if (command=="create_bank"){create_bank(arguments);}` and `if (command=="create_customer"){create_customer(arguments);}` etc. – Slazer Nov 29 '15 at 09:59
  • @IgorTandetnik I can at least move it. If explicit means there is no conversion (typecast) possible, the question is answered. – Slazer Nov 29 '15 at 10:02
  • 1
    No *implicit* conversion is possible from `string` to `istringstream`. You can of course convert explicitly. [Something along these lines](http://rextester.com/AJUMH33695). Personally, I fail to see the point of the exercise. – Igor Tandetnik Nov 29 '15 at 14:44

2 Answers2

1

I'd just use a std::string as a parameter. But if you want to pass a std::istringstream, then you need to pass it explicitly to f, as the std::istringstream constructor that takes a std::string is marked explicit (#2). Example:

f(std::istringstream{"create_customer 1 Ben Finegold"});

The code above constructs a temporary std::istringstream as the argument, which is then moved into the parameter command of your function; it uses the move constructor #3 from here.

Note that we don't need the clunky

f(std::istringstream{std::string{"create_customer 1 Ben Finegold"}});

because the const char* constructor of std::string is not explicit (#5), and the compiler is allowed to perform at most one implicit user-defined conversion. Therefore in the first code line I posted the string literal "create_customer 1 Ben Finegold" is converted to a std::string, which is then used to explicitly construct the temporary std::istringstream argument, which is then moved into command.

vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • I think you forgot to mention I need to change `istringstream command` to `istringstream&& command` in `f()`. However, my idea was to pass a `string` to `f()`, let `f()` create the `istringstream` transparently and make it available in the body **without** any code creating it in the body. Is this possible? – Slazer Nov 29 '15 at 09:50
  • @Slazer I don't think you want to have a `istringstream&&` argument, unless you don't really want to move from your destination and just "inspect" the rvalue reference. In the solution I posted `command` is a parameter into which you move an `istringstream`, that is created when you invoke the function. There is no `istringstream` creation code in the body. I don't think you can do it simpler than that, as there is no implicit conversion from `string` to `istringstream`. – vsoftco Nov 29 '15 at 16:21
0

I'm not quite sure what you are trying to do with that void f(...), but I think this should do what you want:

template<typename... Args>
void f(Args&&... args)
{
    istringstream command(forward<Args>(args)...);
    // You logics...
}

int main()
{
    f("create_customer 1 Ben Finegold"s);
    //...
    return 0;
}

Edit 1

I use variadic template just in case you would like to initialize your local stream with other streams. If string you only need to initialize it with strings, you could do this:

void f(string&& str)
{
    istringstream command(forward<Args>(str));
    // You logics...
}

which is essentially the same.

Lucien
  • 134
  • 5