7

Pretty sure I know the answer to this one (thinking no), but could one safely accept/return std::function by value in an API (across module boundaries)?

I'm thinking 'no' as I don't think there are any guarantees that one vendor's std::function implementation is compatible with the other's. Is that the case?

If the answer is no as I suspect, how do you all deal with this kind of thing? I might have to resort to implementing my own or just avoid things like std::function all together (ex: work with function pointers or functionoids). :-( I've found myself doing that in many cases before (reinventing a lot of the standard C++ library and certainly regrettably as even making our own STL-compliant vector type with support for both range ctor and fill ctor, custom allocators, etc. was certainly not fun and I doubt it was as good as standard implementations) simply because one might dynamically link to a library that has, say, MSVC 2010's implementation of std::function from a binary written in mingw, e.g.

The alternative, of course, is to not use these kinds of C++ features at all in our API and use, say, a C interface, but that would come at a rather heavy cost to us since we use our API as the central API for both internal and third party development.

Dev Null
  • 4,731
  • 1
  • 30
  • 46
stinky472
  • 6,737
  • 28
  • 27
  • 2
    This is just the same problem as *any* compiled C++ library faces... – Kerrek SB Feb 26 '12 at 21:02
  • 1
    @KerrekSB: Not a static library. Just DLLs that try to use standard library types across DLL boundaries. It isn't save with C types either (like `FILE*`), but you generally don't see people wanting to fling them across DLLs. – Nicol Bolas Feb 26 '12 at 21:05
  • 1
    Seems that way. I always wondered how people deal with it (ex: if there are some cross-compiler alternatives we could use that could work across module boundaries by, say, distributing that source code with our SDK). Always wished there was more attention paid to the use of C++ across module boundaries since we centralize development through our API implemented in a DLL/shared library and something like std::function is so useful in place of regular callbacks or functionoids, especially with the addition of lambda expressions. – stinky472 Feb 26 '12 at 21:06

1 Answers1

9

You can do it, so long as everyone's playing by the same rules, and your standard library is dynamically linked. If third-parties know that they must use a certain compiler, and a certain version of that compiler, with certain specific build flags, then there's no problem.

Even if you write your own wrapper, they have to use a specific version of that wrapper, though obviously that's a bit easier to enforce.

But really, that's the price you pay for trying to inter-operate via DLLs: everyone has to be on the same page, or else it won't work. Or you have to stick with basic types or home-grown, controlled interfaces.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 1
    I see, thanks. The home-grown solution is what we've been doing for the most part but it becomes quite a pain to replicate the usefulness of some essential standard library types like vector, wstring, unique_ptr, shared_ptr, function, etc. that can be so nice for building public interfaces. Almost temps me to start an open source, minimalistic, cross-compiler solution to these things if no one has done so already. We were thinking of doing that with boost but that also becomes somewhat tricky since boost is so huge and a developer might want to use a newer version than what we distribute, e.g. – stinky472 Feb 26 '12 at 21:10
  • boost is something we've considered distributing but it's a bit difficult because it's so large and we've often wondered what would happen if third parties are already using a version of boost different from what we distribute. It would make our SDK many times bigger than it is and it's a bit tough to just use certain sections of it since a lot of the features are built from other parts of boost. Maybe we should look at it again since boost::function would work quite well in this case and it is certainly very good about supporting many different compilers. – stinky472 Feb 26 '12 at 21:15
  • 1
    @stinky472: Then you need to make a choice: how much restriction do you want to put on third parties vs. how much restriction do you want to put on your API? Also, note that `boost::function` for one compiler is not guaranteed to interop with `boost::function` for another compiler. I wouldn't even suggest that kind of interop with home-grown types, due to possible padding/alignment differences between compilers. If you need someone to work in a different compiler than the one you use, then you need to stick to basic types across DLL boundaries. – Nicol Bolas Feb 26 '12 at 21:35
  • That makes sense. In practice we've found some degree of comfort with interoperability (ex: requiring certain settings for structure padding as long as there exists a solution that at least supports popular compilers). We do try to stick to lowest common denominator approaches where practical (ex: accepting const pointers and sizes rather than, say, a vector, as that also makes the API a bit more flexible by only requiring that the representation is contiguous). In other cases we've used a hybrid of a lower-level API with very restricted types while providing wrappers on top of it that... – stinky472 Feb 26 '12 at 21:48
  • ... provide more convenient interfaces where we're free to use whatever standard library functionality we want since all that wrapper code is statically linked. I might try exploring that route further... toying with the idea of making it easy to translate from something like std::function to a functionoid, e.g. – stinky472 Feb 26 '12 at 21:50