Johannes
Johannes

Reputation: 6707

How can a header file safely include standard libraries for consumers to import them

Suppose I want to create the the Following class:

#pragma once
#include <memory>
#include <string>

namespace stackquestion
{
    struct Logger
    {
        void Log(std::string message);
    private:
        class Impl;
        std::unique_ptr<Impl> impl;
    };
}

When I want to publish the class I end up depending on my consumers definition of std::string and std::unique_ptr. I am vague on the meaning of publish. I am thinking of handing someone a library either for static or dynamic linking.

When I fall back to a version without those includes I end up losing the comfort / safety that I wanted to gain.

#pragma once

namespace stackquestion
{
    struct Logger
    {
        void Log(const char *);
    private:
        class Impl * impl;
    };
}

Is there a silver bullet that I am missing?

Upvotes: 0

Views: 64

Answers (1)

JVApen
JVApen

Reputation: 11317

Both solutions are fine, depending on what your goal is.

Including memory and string

Doing this, doesn't break code, you do force them to have C++11 or above to use your library. However, I see this as a plus point as you don't have to mess around with a lot of tricks to support C++98.

When compiling the code, they shouldn't mess with the standard library, so if they do something like #defined unique_ptr shared_ptr I would blame your users for bad coding, not you. And yes, you could try to protect from a lot of bad stuff done by the users, as overloading operator& (address of), however, you would end up with code like the STL implementations, which ain't pretty either.

Using pimpl

Using pimple resolves a lot of the issues mentioned above. However, you shouldn't use it because of that. The only real advantage of pimple is binary compatibility.

As you don't expose the STL or any other libraries except for your own, you shouldn't get link errors on std::string. (Yes, this is possible)

If you compile your library with libc++, std::string is actually std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > with a memory layout specific for libcxx.

If you compile your library with libstdc++, std::string becomes std::basic_string<char, std::char_traits<char>, std::allocator<char> > (or a longer name for the C++11 variant)

See this thread for more details

Upvotes: 1

Related Questions