I'm using a pre-C++11 compiler and I'm trying to "export" a constant, without exposing the classes from which this constant is calculated.
// A.hpp ----------------------
struct A{
...
};
// B.hpp ----------------------
struct B{
...
};
// Manager.hpp ------------------
#include "Manager.hpp"
template <size_t a, size_t b>
struct StaticMax
{
enum { value = a>b ? a : b };
}
class Manager
{
public:
static const size_t OverlayDataSize;
...
};
// manager.cpp ------------------
#include "A.hpp"
#include "B.hpp"
// I want the following constant to be available to anyone
// that includes Manager.hpp, but the classes A and B should not
// be visible to anyone else except class Manager
const size_t Manager::OverlayDataSize = StaticMax<sizeof(A),sizeof(B)>::value;
// otherfile.hpp -------------------
#include "Manager.hpp"
struct OverlayData
{
// shared state goes here
uint8 gameState;
uint8 specificState[Manager::OverlayDataSize];
};
class NvRam
{
void Write(OverlayData& serializedState);
....
}
The above code won't compile and results in:
error: ‘Manager::OverlayDataSize' is not a valid template argument for type ‘unsigned
int’ because it is a non-constant expression
Which is already strange since Manager::OverlaySize most definitely is const and its value is calculated at compile time. But according to this question, if a const declaration and its definition aren't in the same location, then the compiler can't use it as a constant. The error persists even if you use a global variable declared with extern. I could have calculated the maximum size differently by using a union (but then structs A and B aren't allowed to have constructors), but that's not the problem, I still can't export that constant to be available at compile-time without exposing structs A and B to everyone. Of course I can side step the whole issue by making the DataOverlay struct a bit more complicated and using new uint8[Manager::OverlayDataSize]; at runtime and be able to maintain strict seperation. But I'm shooting for this to be done statically at compile time.
So how to "export" a compile-time constant while maintaining strict separation between structs A and B and users of Manager?
Here is a (rather ugly) solution.
The core problem is you only need the size of A and B, which are constants, but you are forced to include the whole definition. The solution would be to manually calculate the size and write it in the required place.
But it is easy to forget to update the value when A and B are modified, so we should somehow automatically do the above job.
To achieve this, you can write a code generator, which generates code like this to a header file:
const size_t OverlayDataSize = /* the calculated size */;
and invoke that program each time you rebuild the whole project. (For example, by writing a Makefile. )
That generator can have A.hpp and B.hpp included, calculate max(sizeof(A), sizeof(B)) and run a printf or something similar to write the generated code. The other source files should only #include the generated source.
Since C++ does not have a module system (which will enable you to hide some internal entities) or a complete metaprogramming facility (which allow us to write some code that generates other code), I can only think of this rather ugly way to achieve this. But anyway, it should work.
Related
I have a bunch of complex classes in one translation unit which involves a bunch of header dependencies. In addition, the translation unit provides a factory function.
// MyClass.h
#include "Interface.h"
// lots of other includes
class MyClass : public Interface {
// lots of members
}:
// Creates an instance of MyClass using placement new
Interface* createMyClassAt(uint8_t* location);
In another translation unit I want to use multiple instances of different classes deriving from Interface and I want to allocate them in static memory. It's a small embedded system without heap. I want to avoid the inclusion of MyClass.h because some its dependencies are internal.
// somefile.cpp
#include "Interface.h"
extern Interface* createMyClassAt(uint8_t* location);
uint8_t myClassContainer[sizeofMyClass];
int main() {
createMyClassAt(myClassContainer);
// more stoff
}
My understanding is, that it is impossible to determine sizeofMyClass without having the actual type information of MyClass. No matter what I do. I cannot get this information across translation units.
How to achieve my goal then? Do I need to go via the build system and extract the sizes somehow from the object files and generate a header from that? That might be OK after all.
Edit 1: Some clarification:
All those classes derived from Interface.h are defined in a prelinked, self-contained static library at the end.
By "internal dependencies" I mean other header files and types that I don't want to leak to consumers of the library
The consumers of the library may create multiple instances of various classes.
Make a second function which returns the size of your class:
extern size_t sizeofMyClass();
size_t sizeofMyClass() { return sizeof(MyClass); }
If you want it at compile time, than constexpr it.
You can declare myClassContainer in the "someFile" translation unit but actually define it in the "myClass" translation unit. This can be made easier with a common header file:
// globaldefs.h
#include <cstdint>
extern std::uint8_t myClassContainer[];
#ifdef MY_CLASS_DEFINED
alignas(MyClass) std::uint8_t myClassContainer[sizeof(MyClass)];
#endif
// MyClass.h
class MyClass : public Interface {
// lots of members
};
#define MY_CLASS_DEFINED
#include "globaldefs.h"
// somefile.cpp
#include "globaldefs.h"
extern Interface* createMyClassAt(uint8_t* location);
int main() {
createMyClassAt(myClassContainer);
// more stuff
}
That way, the translation unit with somefile.cpp only sees std::uint8_t myClassContainer[];, and no size is needed.
How to achieve my goal then?
Approuch 1: static assert and "gueess" sizes. There is no dependency between interface.h and the class, but you have to manually update the header on each change (or, better, generate the header from the build system).
// interface.h
using Interface_storage = std::aligned_storage<20, 16>;
// ^^^^^^ - size and alignment
// They are _hard-coded_ here and _need_ to be _manually_ updated each time
// MyClass changes.
Interface* createMyClassAt(Interface_storage& location);
// interface.c
Interface* createMyClassAt(Interface_storage& location) {
// static assertion check
static_assert(sizeof(MyClass) == sizeof(Interface_storage) &&
alignof(MyClass) == alignof(Interface_storage),
" Go and fix the header file");
// use placement new on location
}
// main.c
int main() {
Interface_storage storage; // nice&clean
Interface *i = createMyClassAt(storage);
destroyMyClassAt(i, storage);
}
Approuch 2: Unix systems since the ages used file descriptors. A file descriptor is simple - it's just an index in an array of... somethings. It's trivial to implement, and you can hide everything behind a single integer value. That basically means, that you have to use dynamic memory, or you have to know in advance how many objects you need and allocate memory for all of them.
The below pseudocode implementation just returns the pointer to the interface, but it's very similar to returning an index in the array just like file descriptors.
// interface.h
Interface *new_MyClass();
destroy_MyClass(Interface *);
// interface.c
#define MAX 5
std::array<std::aligned_storage<sizeof(MyClass), alignof(MyClass)>, MAX> arr;
std::array<bool, MAX> used;
Interface *new_MyClass() {
// find the fist not used and return it.
for (size_t i = 0; i < used.size(); ++i) {
if (!used[i]) {
used[i] = true;
return new(arr[i]) MyClass();
}
}
return nullptr;
}
void destroy_MyClass(Interface *i) {
// update used array and destroy
}
This is a second attempt to answer the question.
You cannot do what you want. The only reason to hide the implementation (PIMPL) is to allow you to compile the module completely independently.
You cannot do this, whilst at the same time as injecting a dependency. What you ask for is self-contradictory.
Either declare the class in the header, so that the dependency is declared, or put the array in the module that contains the class. If its a static array, why does it matter which module it is declared in.
In other words, use a singleton, accessible via a free-function
I'm learning C++ using Xcode and have written several small programs including a hangman game but I'm having trouble every time I try to separate a class into definition and implementation. I made a simple case that shows my problem. Short version is it seems that I need to specify a type in the implementation file even though it is already defined in the header file. I get "C++ requires a type specifier for all declarations" on lines 12 and 13 in my example. But if I change line 12, for example, to
int xmlelem::atrb_count = 0;
it gets the error "non-static data member defined out-of-line". In other cases I have got an error saying that I was trying to redefine something. I think I'm missing a fundamental concept somewhere. I did not see this particular issue in the handful of similar questions I looked at.
xmlelem.hpp
// xmlelem.hpp
// learn header
//
//
#ifndef xmlelem_hpp
#define xmlelem_hpp
#include <stdio.h>
#include <string>
#endif /* xmlelem_hpp */
class xmlelem {
private:
int atrb_count;
std::string tag_name;
public:
xmlelem(std::string tag);
void add_atrib();
std::string output();
};
xmlelem.cpp
// xmlelem.cpp
// learn header
//.
//
#include "xmlelem.hpp"
#include "string"
#include <iostream>
// line 11
xmlelem::atrb_count = 0;
xmlelem::tag_name = "";
xmlelem::xmlelem(std::string tag){
tag_name = tag;
}
void xmlelem::add_atrib(){
atrb_count++;
}
std::string xmlelem::output(){
std::string build = "<";
build = build + tag_name + " " + std::to_string(atrb_count);
build = build + ">";
return build;
}
and main.cpp
// main.cpp
// learn header
//
//
#include <iostream>
#include "xmlelem.hpp"
using namespace std;
int main(){
xmlelem clip("test)");
std::cout << clip.output() << " test \n";
}
Let's take a look at the (second) error message.
non-static data member defined out-of-line
There are two parts to the error: "non-static data member" and "defined out-of-line". These are incompatible, so one of them must be changed. Furthermore, only one of them should be changed, or else you may run into a different problem. Decide which of the two parts is correct for your situation.
Keep "defined out-of-line"
When the line
int xmlelem::atrb_count = 0;
is encountered at namespace scope (that is, in neither a function nor a class/struct/union definition), it is an out-of-line definition. This definition tells the compiler to reserve, right at that spot, enough space for an int. Then whenever any xmlelem object accesses the atrb_count member, it will access this particular space. So there is one int shared by all objects.
However, this behavior corresponds to a static member. To make the declaration agree with the implementation, the keyword static needs to be added.
class xmlelem {
private:
static int atrb_count;
/* rest of the class definition */
};
Keep "non-static"
A non-static data member is stored inside each object of the class. Each object can do what it wants with its copy of the data without impacting other objects. So telling the compiler to reserve space outside the objects is contradictory. Simply removing the out-of-line definition is enough to get rid of the error message, but presumably you wanted that initialization to occur somewhere, right?
The initialization of non-static data members can be done either in-line or in a constructor. An example of moving the initialization in-line is the following.
class xmlelem {
private:
int atrb_count = 0;
/* rest of the class definition */
};
This is sometimes reasonable, but the stated goal was to separate the interface from the implementation. Therefore, it might be undesirable for the initial value of 0 to appear in the header file, as it does in the above. The alternative is to move the initial value to the constructor (to each constructor, if you had more than one).
xmlelem::xmlelem(std::string tag) :
atrb_count(0),
tag_name(tag)
{
}
(I've also taken the liberty of moving the initialization of tag_name into the initialization list.)
Remember, if you have more than one constructor, this needs to be done in each constructor that actually utilizes the default value (for an exception, think "copy constructor"). Repeated code is a drawback; it is up to you to decide if the gains are worth the cost.
Remember that you are declaring a class. A class is an abstract concept. When you do this xlemem::atrb_count = 0;, you are having a concrete value on an abstract concept. Doesn't make sense, right? You don't think of a particular color when you think of the general concept of dog. Any initiliazations should be done inside the constructor, because only in the constructor is that we create a concrete object.
Therefore, you should eliminate lines 11 and 12 where you initialize these 2 attributes and your constructor code should be changed to:
xmlelem::xmlelem(std::string tag){
tag_name = tag;
atrb_count = 0;
}
Note that it isn't necessary to initialize a string to "".
So I've been interested by the mersenne_twister engine and what it can do, so I decided to put the few lines of code required to initialize it inside my own class so that i simply have to create an instance of that class and can get any random numbers in any range i want without having to repeat those lines every time I need it.
I have suceeded so far but because I want my code to be as portble and efficient as possible I want to use the 64-bit engine depending on the architecture present.
I would like to avoid the way of using preprocessor macros defined by the compiler as that doesn't seem like the cleanest approach to me and would also require me to use the macros every time i mention the engine in my code.
My macro for the architecture l looks like this:
#define CPU_ARCH sizeof(nullptr)*8
And I declare the engine in the private space of the class so that i can init it in the constructor like this:
engine = mt19937(seed);
and use it in my random function like this:
double Random::giveRnd() {
return distribution(engine);
}
This looks fine right now but I have yet to find a way to implement both architectures with the same name "engine" in a way that the engine to be used is chosen at startup.
I have attempted the following:
Using a template to create a variable named engine that later gets
assigned either mt19337 or mt19337_64 which results in the compiler
complaining that
error: data member 'engine' cannot be a member template
with the following implementation:
class Random {
public:
[...]
private:
template<typename T>
T engine;
[...]
};
Using boost::variant which requires me to tell
my giveRnd() function which type to use when I use the engine which
is not possible since the type is not known at compile time
Not declaring the engine in the header file at all although this
results in the giveRnd() function not being able to use the engine
because it is not in the same scope.
Using preprocessor macros in the header file and then use typeid in
the source code to find out which engine was used, which doesn't seem
to be possible like this:
if(CPU_ARCH==32) { engine = mt19337(seed) }
because the compiler doesn't know that the engine will always be
32-bit in this case and complains that I cannot use the '=' operator
on two different types.
Does anyone have an idea on how to make this possible in a atleast somewhat clean way? Or do I need to fall back on the preprocessor macros?
You can implement behaviour that depends on CPU_BITS by making a class template that takes CPU_BITS as a template argument, and is specialized for expected values. For example:
#include <random>
template<size_t N> struct CpuOpts;
template<> struct CpuOpts<32> { using EngineType = std::mt19937; };
template<> struct CpuOpts<64> { using EngineType = std::mt19937_64; };
enum { CPU_BITS = sizeof(nullptr)*8 };
using CurrentCpuOpts = CpuOpts<CPU_BITS>;
struct Random
{
CurrentCpuOpts::EngineType engine;
};
int main()
{
Random r;
r.engine.seed(123456);
}
I am working on a project that has a lot of trait types. If I compile every trait in the same code base, the released binary would be quite big.
I am thinking about to use macro to build a binary for each specific trait --- from a business logic perspective, this makes perfect sense.
However, I realized that, if I want to cut down the code base, I need to have this long if/elif pile at the end of each template cpp file. This sounds like a very tedious thing to do.
I am wondering if you have encountered this kind of problem before, what's the most neat solution here?
#include "MyTraits.hpp"
#include "Runner.hpp"
int main(){
#if defined USE_TRAIT_1
Runner<Trait1> a;
#elif defined USE_TRAIT_2
Runner<Trait2> a;
#elif defined USE_TRAIT_3
Runner<Trait3> a;
#endif
return 0;
}
If you want to explicity instanciate templates in specific compilation units you should use the extern template keyword.
// Runner.hpp
//define your template class
template <class runner_trait>
class Runner {
...
};
//This tells the compiler to not instanciate the template,
// if it is encounterd, but link to it from a compilation unit.
// If it is not found, you will get a linker errer.
extern template Runner<Trait1>;
extern template Runner<Trait2>;
extern template Runner<Trait3>;
Runner_trait1.cpp
// the template class keyword tell the compiler to instanciate the template in this compilation unit.
template class Runner<Trait1>;
// The files for Runner_trait2.cpp and Runner_trait3.cpp look identical,
// except for the trait after Runner
I'm not entirely sure that my answer will address the root cause of the problem. But the proposed solution may at least look a bit more "neat".
The basic idea behind the proposal by #JeffCharter makes sense, but I don't like the idea of embedding the code (in this case type names) into the makefile. So I elaborated on it a bit, with the following goals in mind:
Make the contents of main() short and easy to understand
Avoid polluting the makefile
Avoid the macro usage to the most possible extent
I ended up with the following solution which requires a single numeric macro which can be defined in the makefile. Be aware that it uses C++17's constexpr if, so in case you find it useful make sure your compiler supports it.
constexpr int traitID = TRAIT_ID; // TRAIT_ID is a macro defined somewhere else.
template <typename T>
struct Wrapped // helper struct
{
using Type = T;
};
auto trait()
{
// Although it may look not that different from macros, the main difference
// is that here all the code below gets compiled.
if constexpr (traitID == 1)
return Wrapped<Trait1>{};
else if constexpr (traitID == 2)
return Wrapped<Trait2>{};
else if constexpr (traitID == 3)
return Wrapped<Trait3>{};
// add more cases if necessary
}
int main() // the contents of 'main' seems to have become more readable
{
using Trait = decltype(trait())::Type;
Runner<Trait> a;
return 0;
}
Also, here's a live example at Coliru.
I am working on an OpenCL Program which uses the "cl_khr_byte_addressable_store" extension to allow for byte level writes in Kernel code; in order for my program to also work on GPUs which do not support the extension, I need to check whether the extension is available and use an int type instead of char on platforms on which it is not.
In the kernel code, I can simply add the following snippet and use writeable_type throughout the my kernel code; the preprocessor definition cl_khr_byte_addressable_store is automatically added by the OpenCL Kernel compiler iff the extension is available.
/* kernel.cl */
#ifdef cl_khr_byte_addressable_store
typedef char writeable_type;
#else
typedef int writeable_type;
#endif
f() {
writeable_type x = 1;
}
In my host code I don't have that preprocessor definition, and (as far as I know) the check whether extensions are available or not can only be done at run-time:
/* host.cpp */
void execute() {
std::string extensions;
this->opencl->getExtensions(extensions);
if (extensions.find("cl_khr_byte_addressable_store") != std::string::npos) {
// extension is available
typedef cl_char writeable_type;
}
else {
// extension is not available
typedef cl_int writeable_type;
}
writeable_type x = 1;
}
And that's my problem; because typedefs are resolved at compile time and only valid within the block in which they are defined, the example above does not work.
Is it possible to somehow do this anyway?
Thanks rlc, Neil Butterworth and talonmis for putting me on the right path! The solution to my problem turns out to be fairly simple:
/*host.cpp*/
void execute() {
bool extension_available = ...;
if (extension_available)
this->_execute<cl_char>();
else
this->_execute<cl_int>();
}
template <typename writeable_char>
void _execute() {
writeable_type x = 1;
// ...
}
if you have all your code in a class of which the public functions are agnostic of the type, you can do something like this:
// assuming these are defined in OpenCL somewhere
typedef char cl_char;
typedef int cl_int;
// the public part of the base class cannot use the
// writable size because it cannot know the size of the writable type
class Base
{
public :
/* stuff */
virtual void doStuff() = 0;
/* more stuff */
};
// the writable type's size is known in this class and is
// either cl_char or cl_int, so this is where data that has
// to know the size will be carried around, and where API calls
// that need to know the exact writable type go.
// Code that is agnostic of the writable type need not be here
// (but can be)
template < typename WritableType >
class Derived : public Base
{
public :
virtual void doStuff()
{
/* do stuff */
}
};
int main()
{
bool condition(false);
/* magic to check for type size here */
// once you get here, you know what the writable type is going to be,
// so you can create an instance of the derived class accordingly
Base *o;
if (condition)
{
o = new Derived< cl_char >;
}
else
{
o = new Derived< cl_int >;
}
// as of here, you no longer need to know what the writable type
// is because that knowledge is encapsulated in the object o
o->doStuff();
}
i.e. template the class that does everything according to the type you need at run-time, and use the version you need.
All types in C++ must be known at compile time - no exceptions to this rule are possible (this is true for C too). And given the way the language is defined, attempts to redefine types at runtime simply do not make sense. If you find you think you need to do this, there is something way wrong with your design.
You will have to do runtime checking of the options the target OpenCL platform uses and react accordingly. Call clGetPlatformInfo with the CL_PLATFORM_EXTENSIONS query, and you will get back an array of characters which can be parsed to check whether cl_khr_byte_addressable_store is supported. Then choose paths with either integer or character types accordingly.
Most of the vendor SDKs include some kind of device query app which contains examples of clGetPlatformInfo usage. You should be able to crib some code from there.
You're trying to alter a variable at compile-time depending on the value of something at run-time. Unless you either bring compile-time forward to run-time, such as with JITs or interpretation, or invent time travel, then the laws of physics dictate the impossibility of what you want.
Of course, you could also just remove the dependency using inheritance and virtual functions.