9
\$\begingroup\$

I have a need to process URIs in one of my applications, sometimes from const char[] literals.

My API:

namespace net {
    class uri { ... }; // contains decomposed URI (path, parameters, etc)

    uri parse_uri(const std::string& uri_str); // parse string and return uri instance
}

// within global namespace (this is what the question is about):
uri operator "" _uri(const char*str, const unsigned long size)
{
    return net::parse_uri(std::string{str, str + size});
}

Client code:

auto x = "/static/path/here/image.jpg"_uri;

I tried defining the string conversion operator within the net namespace, but (disimilar to other operators) it seems I have to explicitly specify access to it in client code (with using namespace net; for example).

My question:

Does this clash with the "compiler searches for operators in the namespace of the object it applies to" rule (like it would for an operator+(uri&, uri&) for example)? (As a rule of thumb, I assume the problem is with my code, not the compiler).

What is the best practice or policy to use here? Import the namespace / operator in client code, or pollute the global namespace (like I did)?

I am using CLang 5.1 on OS X.

\$\endgroup\$

1 Answer 1

13
\$\begingroup\$

I would follow the way user-defined literals are used in the C++14 standard library: put them in a literals subnamespace that can be imported by the user. This subnamespace would be inline so that it can be imported alone, or automatically imorted when the namescape net is imported:

namespace net {
    class uri { ... }; // contains decomposed URI (path, parameters, etc)

    uri parse_uri(const std::string& uri_str); // parse string and return uri instance

    inline namespace literals
    {
        uri operator "" _uri(const char*str, const unsigned long size)
        {
            return net::parse_uri(std::string{str, str + size});
        }
    }
}

Then, a client code could use your literal with the following code:

int main()
{
    // Import only the literal, not the rest of net
    using namespace net::literals;

    auto x = "/static/path/here/image.jpg"_uri;
}

I actually slightly simplified the way user-defined literals are used in the standard library for your example: there are actually nested inline namespaces in namespace literals so that a more precise selection of related literals can be done if needed (for example, import only the std::chrono-related literals). Since you have only one literal, you don't need to have so many nested namespaces, but you can still add them later if needed.

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.