ThatsJustCheesy
ThatsJustCheesy

Reputation: 1489

Calling Functions With std::optional Parameters

I have a function whose signature is:

void func(std::optional<std::string> os = std::nullopt);

(I’m aliasing std::experimental::optional until std::optional is officially available.)

However, I’m having difficulty calling it cleanly. The compiler will refuse to perform two implicit conversions (const char*std::stringstd::optional<std::string>) to call it with a raw C-string literal. I can do this:

func(std::string("Hello"));

And the compiler will figure that a std::optional is needed, and do the conversion. However, this is way too verbose. Thanks to C++11, I can also do this:

func({"Hello"});

While this is way better, it's still not ideal. I'd like to be able to call this function like any other that takes a std::string. Is this possible? Making the function take another parameter type is okay, as long as it behaves similarly to/is directly convertible to std::optional. Thanks.

Upvotes: 17

Views: 10359

Answers (2)

Guillaume Racicot
Guillaume Racicot

Reputation: 41760

You can do that with a bit of templates and sfinae:

template<typename T, std::enable_if_t<
    std::is_constructible<std::string, T>::value &&
    !std::is_constructible<std::optional<std::string>, T>::value>* = nullptr>
void func(T&& s) {
    void func(std::string(std::forward<T>(s)));
}

This overload will be picked when a string would be constructible with a forwarded T but only when std::optional<std::string> is not constructible.

You function will be callable with any object that a string can be constructed with:

func("potato"); // working, forward the string literal to a std::string

Upvotes: 8

Ivaylo Valchev
Ivaylo Valchev

Reputation: 10415

C++14 adds a bunch of user-defined literals to the standard library in order to make code less verbose. It looks something like this:

using namespace std::string_literals;              // needed
// using namespace std::literals;                  // also ok, but unnecessary 
// using namespace std::literals::string_literals; // also ok, but why??

int main()
{
    std::string str = "string"s;
                       ^^^^^^^^
                       // This is a std::string literal, 
                       // so std::string's copy constructor is called in this case
}

Also take a look at this and this for reference.

Upvotes: 16

Related Questions