HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppModerate

User defined string literals and namespace use

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
literalsuserandusenamespacestringdefined

Problem

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.

Solution

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.

Code Snippets

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});
        }
    }
}
int main()
{
    // Import only the literal, not the rest of net
    using namespace net::literals;

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

Context

StackExchange Code Review Q#49502, answer score: 13

Revisions (0)

No revisions yet.