1

I have some constexpr functions that allow me to simply change the behavior of my algorithm. The functions deduce their return values from some variables. A minimal example looks like this:

// A.h
constexpr std::array<int,3> a = {1,2,3};

constexpr int Foo() {return a[1]*a[2];}
constexpr int Bar() {return a[3];}

Now, all this is implemented in a header file, because I want the methods to be inlined. However, I do not want to expose a to anyone including A.h. How can I achieve this?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
SamVanDonut
  • 361
  • 2
  • 14
  • 2
    As `constexpr` implies `inline`, and `inline` requires every caller to have encountered a definition of the function, and these definitions require to know `a`, I think you're toasted. Would a `detail` namespace be enough? – Quentin Nov 26 '18 at 10:04
  • Yes-no. I knew of the `detail` namespace concept, but was hoping there would be something more sophisticated. Thank you, anyways! – SamVanDonut Nov 26 '18 at 11:10
  • 1
    You can also make `a` a private member of a class, and then make the public stuff (`Foo()`, `Bar()`) into `friend` functions. `a` will still exist in the source code everyone sees, but the compiler will do a much better job of blocking ill-advised direct accesses. – Ben Voigt Nov 26 '18 at 14:40
  • I think you can use extern for this, see https://stackoverflow.com/questions/30208685/how-to-declare-constexpr-extern/53277889 but it counteracts against the inline optimizer. – gast128 Nov 26 '18 at 15:06

2 Answers2

2

In a pre-module C++ world, your options are limited. The common idiom for having to expose definitions of things you would rather users not see is to create a so-called "detail" namespace. This is a namespace, typically named detail or something to that effect, which contains all the stuff that is not part of your interface. By convention, users should not access stuff in that namespace.

You could make a private, static constexpr member of some class. This would more effectively prevent users from being able to access it. But it has the downside of making it so that you have to friend every function that uses it.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • That's pretty much the ideas I had as well. I asked here to make sure I'm not overlooking something. Thank you. – SamVanDonut Nov 26 '18 at 17:00
0

If your function are not members of the class, you can have:

  • public_a.h (visible to users of a.cpp)
  • private_a.h (included by a.cpp, located with your source)
  • a.cpp

and place the function in the right place. You just have to be sure a.cpp can be used by someone #including only public_a.h.

You could also have a publicly-visible base class offering the API you want and hide the customization in derived classes, but that adds extra complexity like a factory method.

Jeffrey
  • 11,063
  • 1
  • 21
  • 42
  • If I recall correctly, C++17 does not allow `virtual` functions to be `constexpr` (that is I believe a C++20 feature). So the whole base/derived class thing is a non-starter. Also, all of the OP's stuff is `constexpr`, which *must* have their definitions exposed, so putting them in a .cpp file is also a non-starter. – Nicol Bolas Nov 26 '18 at 15:32
  • My reading is that OP must have at least some code not inlined in the header file. Otherwsie, what would be the point of not exposing some code, if all the rest is ? – Jeffrey Nov 26 '18 at 15:41
  • So that people don't think that an implementation detail is part of the interface. `Foo` and `Bar` are user interfaces that are stable APIs. `a` is an implementation detail, so it is subject to change. Therefore, you shouldn't look at it directly. The way this is normally done is that the header includes only the things that are interfaces. But inlining, constexpr, and templates make this difficult. That's yet another reason why C++ needs modules. – Nicol Bolas Nov 26 '18 at 15:44