Testing template to memory location to replace defines in embedded systems - c++

In embedded systems, you often have a memory location which is not within the program memory itself but which points to some hardware registers. Most C SDKs provide these as #define statements. According to the following article, https://arne-mertz.de/2017/06/stepping-away-from-define/ one method of transitioning from #define statements (as used by C SDKs) to something more C++ friendly, is to create a class which forces reinterpret_cast to occur at runtime.
I am trying to go about this in a slightly different way because I want to be able to create "type traits" for the different pointers. Let me illustrate with an example.
#define USART1_ADDR 0x1234
#define USART2_ADDR 0x5678
template <typename T_, std::intptr_t ADDR_>
class MemPointer {
public:
static T_& ref() { return *reinterpret_cast<T_*>(ADDR_); }
};
class USART {
public:
void foo() { _registerA = 0x10; }
private:
uint32_t _registerA;
uint32_t _registerB;
};
using USART1 = MemPointer<USART, USART1_ADDR>;
using USART2 = MemPointer<USART, USART2_ADDR>;
template <typename USART_>
class usart_name;
template <>
class usart_name<USART1> {
public:
static constexpr const char* name() { return "USART1"; }
};
template <>
class usart_name<USART2> {
public:
static constexpr const char* name() { return "USART2"; }
};
Each USART "instance" in this example is its own, unique type so that I am able to create traits which allow compile-time "lookup" of information about the USART instance.
This actually seems to work, however, I wanted to create some test code as follows
static USART testUsart;
#define TEST_USART_ADDR (std::intptr_t)(&testUsart);
using TEST_USART = MemPointer<USART, TEST_USART_ADDR>;
Which fails with the following error:
conversion from pointer type 'USART*' to arithmetic type
'intptr_t' {aka 'long long int'} in a constant expression
I believe I understand the source of the problem based upon Why is reinterpret_cast not constexpr?
My question is, is there a way to make my MemPointer template work for test code like above as well?
EDIT
One solution is to have a separate class for each "instance" has follows
class USART1 : public USART {
public:
static USART& ref() { return *reinterpret_cast<USART*>(USART1_ADDR); }
};
class USART2 : public USART {
public:
static USART& ref() { return *reinterpret_cast<USART*>(USART2_ADDR); }
};
I would prefer some sort of template + using combination though so that I don't need to write a bunch of classes. But perhaps this is the only option.

is there a way to make my MemPointer template work for test code like above as well?
You could just stop insisting that the address be an intptr_t. You're going to cast it to a pointer anyway, so why not just allow any type for which that conversion exists?
template <typename T_, typename P, P ADDR_>
class MemPointer {
public:
static T_& ref() { return *reinterpret_cast<T_*>(ADDR_); }
};
using USART1 = MemPointer<USART, std::intptr_t, USART1_ADDR>;
using USART2 = MemPointer<USART, std::intptr_t, USART2_ADDR>;
static USART testUsart;
using TEST_USART = MemPointer<USART, USART*, &testUsart>;
Follow-up notes:
if this were for a library to be used by others, I'd consider adding a static_assert(std::is_trivial_v<T_>) inside MemPointer to catch annoying errors
there are a few potential issues around things like padding & alignment, but I assume you know what your particular embedded platform is doing
you should volatile-qualify your register members, or the whole object (eg. you can return std::add_volatile_t<T_>& from MemPointer::ref)
This is so the compiler knows that every write is an observable side-effect (ie, observable by the hardware even if your program never reads it back), and that every read may produce a different value (because the hardware can update it even if your program doesn't).

Related

can i cast a template instance with arg uint to same template instance with arg int - is it compliant - to which standard?

Plz check following c++ code: (nothing special, should be compliant to c++ 2nd edition from 1991)
class C
{
// also defines all the methods called in template method below with the obvious name and args.
public: template<typename TEnum> void SetNullableEnumValuePtr(CNullable<TEnum>* aEnumPtr)
{
if(sizeof(TEnum) == 4)
{
this->SetNullableUInt32Ptr(reinterpret_cast<CNullable<UInt32>*>(aEnumPtr));
}
else if (sizeof(TEnum) == 2)
{
this->SetNullableUInt16Ptr(reinterpret_cast<CNullable<UInt16>*>(aEnumPtr));
}
else if (sizeof(TEnum) == 1)
{
this->SetNullableUInt8Ptr(reinterpret_cast<CNullable<UInt8>*>(aEnumPtr));
}
else
{
this->FailEnumSize();
}
}
}
basic conditions
class CNullable follows the well known, basic nullable pattern implemented i.e. for c# in certain frameworks but could also be any template with one argument.
as the names imply, TEnum is used for different enum types. i.e. enum FooEnum { foo };
For different platforms/compilers it is true, that with for the same enum type it goes to different if branches: On Win32 all enums are compiled with a size of 4 bytes always. On my MCU it compiles to uint8, if the values of the enum field implies to do so.
1. Not my focus:
i'm not sure, if the c++ standard allows compliant compilers to generate enums with different sizes in respect of the required size but i think it is said, that it is compliant.
2. not my focus:
it is also obvious that a cleaner / more robust solution would generate explicit template instances for the function for ALL used enum types. however i might do this and hope the compiler/optimizer is smart/compliant enough not to generate extra code for all types.
3. Not my focus:
i know that reinterpret_cast can be evil but there is a reason the c++ standard defines it. so please stop downrating my questions just because you dont like it or dont understand it.
4. Not my focus:
i know there are certain websites, you can test code on different compilers.
5. would help too:
also if you have a better idea how to treat this coding issue you're welcome.
6. My focus:
i wanna focus this question on the issue, if the c++ standard [1] (or any other standard) defines rule(s), that the templates instances for intXX and uintXX (Where XX is the bit width and u indicates a unsigned version of the native integer) must forcefully compile to a code where a reinterpret_cast from CNullable<unsigned intXX> to CNullable<intXX> is guaranteed to run properly. it seems to be likely that a straight forward implementation of the tool chain may not cause problems in this case, but i got used to be carefull with such assumptions.
conclusion:
if one could give me the reference(s) to chapter inside the (c++) or other standard treading these issues (1 to 6) - that would be great.
thank you!
[1] Please understand the sad reality, that the platform i work on does even not have a ready compiler specification. so it is quite trial and error and i wanna understand the techniques behind to get a better feeling for it - because treading the issue deterministic seems not to be possible since the compiler reference does not give a clear statement what standard it supports: They stated an ETSI standard rather than an iso c++ standard and they didnt give enough info to find the documentation of the standard - no version number, no document number, no document name. when i search for the info given in the compiler documentation on the ETSI page i get > 24.000 results (!) XD
PS: Edit: I request the info:
a) Which standards / specifications ensure that this code runs properly?
b) Does anyone have a clean solution for an abstraction using different template instances for different enum types?
Ok think i i have a clean solution. It uses a wrapper pattern to hide the abstraction of concrete value types behind a virtual method.
I hope that is enough code to get the intention. I also put a very simple example of how i use it.
I guess in newer c++ version there are some stl elements which can replace the classes i wrote. But i need it for a very old c++ standard, which even isn't iso.
I really hope there are no errors since not all symbols are defined. but the essential stuff shall be shown in this example implementation.
// platform dependent UInt32 type.
typedef unsigned __int32 UInt32;
template<typename T>
class CNullable
{
public: bool HasValue;
public: T Value;
public: CNullable(): Value(), HasValue(false) {}
public: CNullable(const T& aValue): Value(aValue), HasValue(true) {}
public: template<typename T1>
CNullable<T1> To() const
{
return this->HasValue ? CNullable<T1>(static_cast<T1>(this->Value)) : CNullable<T1>();
}
CNullable<UInt32> ToU32n() const
{
return this->To<UInt32>();
}
};
// U32-Nullable type
typedef CNullable<UInt32> UInt32n;
// U32-Nullable argument type.
typedef const CNullable<UInt32>& UInt32na;
// Some kind of variant value that can store different types of values pointing into an (intended) statically allocated model
class CValue
{
// Report failure. Break debuger, raise exception, log error - whatever.
private: static void Fail(const char* aTextPtr);
// Sets the value in the (intended) statically allocated datamodel
// Simple example with a UInt32 as new value
public: void SetTargetValue(UInt32na rhs);
// Sets the value in the (intended) statically allocated datamodel
// May use a visitor pattern (GOF) for resolving assigned types, but thats not the topic here.
public: void SetTargetValue(const CValue& rhs);
// Ensures that object is not sealed an fails if so.
private: bool CheckNotSealed();
// Allows to change to sealed state to protect the object agains modification.
// protection for "as static as possible"-memory-design
public: void Seal();
// Base class for Wrappers
class CValueWrapper
{
public: virtual ~CValueWrapper() {}
// Converts the current value as an U32.
public: virtual UInt32n GetInterpretedU32n() { Fail("Data conversion not supported."); return UInt32n(); }
// converts the new value from an U32 and sets the value
public: virtual void SetInterpretedU32n(UInt32na aU32n) { Fail("Data conversion not supported."); }
};
// Wrappers Base class for any enum related type.
class CEnumWrapperBase : public CValueWrapper
{
public: virtual UInt32n GetU32n() const = 0;
public: virtual void SetU32n(UInt32na aU32n) const = 0;
public: virtual UInt32n GetInterpretedU32n() { return this->GetU32n(); }
public: virtual void SetInterpretedU32n(UInt32na aU32n) { this->SetU32n(aU32n); }
};
// Wrapper base class for values of type = Nullable<TEnums>
template<class TEnum> class CNullableEnumWrapper : public CEnumWrapperBase
{
private: CNullable<TEnum>* mNullableEnumPtr;
public: CNullableEnumWrapper(CNullable<TEnum>* aNullableEnumPtr)
:
mNullableEnumPtr(aNullableEnumPtr)
{
}
public: virtual UInt32n GetU32n() const
{
return this->mNullableEnumPtr ? this->mNullableEnumPtr->ToU32n() : UInt32n();
}
public: virtual void SetU32n(UInt32na aU32n) const
{
if (this->mNullableEnumPtr)
{
*this->mNullableEnumPtr = aU32n.To<TEnum>();
}
}
};
// Wrapper base class for values of type = Nullable<TEnums>
template<class TEnum> class CEnumWrapper : public CEnumWrapperBase
{
public: CEnumWrapper(TEnum* aEnumPtr)
:
mEnumPtr(aEnumPtr)
{
}
private: TEnum* mEnumPtr;
public: virtual UInt32n GetU32n() const
{
return this->mEnumPtr ? static_cast<UInt32>(*this->mEnumPtr) : UInt32n();
}
public: virtual void SetU32n(UInt32na aU32n) const
{
if (this->mEnumPtr
&& aU32n.HasValue)
{
*this->mEnumPtr = static_cast<TEnum>(aU32n.Value);
}
}
};
// Allows to lock instantian of wrapper objects.
// In my bare metal application all wrappers are created on application startup
// and stay allocated until the device is switched of (by disconnecting power)
// [ThreadStatic]
public: static bool InstanciateValueWrapperEnabled;
// Set pointer to enum value (intended to be allocated in a static model)
public: template<class TEnum> void SetEnumValuePtr(TEnum* aEnumPtr)
{
if (this->InstanciateValueWrapperEnabled)
{
if (this->CheckNotSealed())
{
this->SetValueWrapperPtr(new CEnumWrapper<TEnum>(aEnumPtr), true);
}
}
else
{
Fail("Invalid operation.");
}
}
// Set pointer to nullable<enum> value (intended to be allocated in a static model)
public: template<class TEnum> void SetNullableEnumValuePtr(CNullable<TEnum>* aEnumPtr)
{
if (this->InstanciateValueWrapperEnabled)
{
if (this->CheckNotSealed())
{
this->SetValueWrapperPtr(new CNullableEnumWrapper<TEnum>(aEnumPtr), true);
}
}
else
{
Fail("Invalid operation.");
}
}
// Sets the member var and data type to 'CValueWrapper' (may support some types natively without a wrapper object)
public: void SetValueWrapperPtr(CValueWrapper* aValueWrapperPtr, bool aOwning);
};
// Model Base Code
//////////////////////////////////////
/// Application specific code
enum FooEnum { FooEnum_Val1 };
// Reads data from StdIn, uart, or whatever.
UInt32 ReadU32();
// Process data, for example output calculated data to another hardware interface.
void Process(CValue** aValuePtrs);
// Simple example of how its being used.
// in real environment its likely to encapsulate a set of CValue objects
// in a ModelInstance-Object and build it by a ModelDefinition object parsing a model definiton language (mdl)
// or adapt generated code. etc. etc...
void main()
{
// Define the static model:
static FooEnum gFooEnum;
static CNullable<FooEnum> gNullableFooEnum;
// Define the values to access the static model
CValue aFooEnumVal;
CValue aNullableFooEnumVal;
// Begin of init:
CValue::InstanciateValueWrapperEnabled = true;
aFooEnumVal.SetEnumValuePtr(&gFooEnum);
aNullableFooEnumVal.SetNullableEnumValuePtr(&gNullableFooEnum);
CValue::InstanciateValueWrapperEnabled = false;
// End of init
// Create an array of values
const UInt32 aPropertyCount = 2;
CValue* aPropertyPtrs[aPropertyCount] =
{
&aFooEnumVal,
&aNullableFooEnumVal
};
for (UInt32 aIdx = 0; aIdx < aPropertyCount; ++aIdx)
{
aPropertyPtrs[aIdx]->Seal();
}
// Very simple and unsave data receiption loop.
while (true)
{
UInt32 aPropertyIdToSet = ReadU32(); // The property id to receive.
UInt32 aNewValHasValue = ReadU32(); // Wether the value is defined
UInt32 aNewValValue = ReadU32(); // The value
UInt32n aNewVal // Nullable for NewValue
= aNewValHasValue // if value is defined
? UInt32n(aNewValValue) // Create a nullable which has a value
: UInt32n() // Create a nullable which has no value
;
CValue* aValuePtr = aPropertyPtrs[aPropertyIdToSet]; // Get the value to receive.
aValuePtr->SetTargetValue(aNewVal); // Set the value to the static model
Process(aPropertyPtrs); // Process data newly received.
}
}

c++ metaprogramming: creating typedef for each enum type member as type

I wonder if it is possible to generate types set from enum class for the metaprogramming purposes.
I'm originally a C# programmer and used to using a lot of attributes for reflection and metaprogramming. For example, it is a general pattern for me to write a snippet like that with C#:
public enum ComponentEnum { Component1, Component2, Component3 }
[Component(ComponentEnum.Component1)]
public class Component1
{
/* Some code */
}
public static class ComponentsMeta
{
private static Dictionary<Type, ComponentEnum> map;
static ComponentMeta() { /*process the whole codebase via reflection, search Component marked classes an fill the map */}
public static bool IsComponent<T>() => map.ContainsKey(typeof(T));
public static int GetComponentUID<T>() => (int)map[typeof(T)];
}
Of course, it is a very basic snippet without asserts and some other stuff but I believe you got the idea.
I want to make the same behavior in the c++ snippet. What I want to do exactly is makes a type called Components that will contain some utility functions like bool Components::isComponent<T>() or size_t Components::getComponentUID<T>() or some related stuff. The best way I've seen so far is to write it down by myself, making a metaclass like
template <typename Ts..>
class ComponentsData
{
/* functions impl here */
}
typedef ComponentsData<C1, C2, C3> Components;
So, now I can ask Components<C1>::getComponentUID() and it returns me uid of that component (depends on its position as template parameter or constexpr value of that component, it doesn't matter). But it is a very inconvenient way to do that and I wonder if I can put a macro inside the component class or using attributes and code generation step or something. In other words, my goal is to mark somehow the class that it should be in that components set and use it later. What c++ can offer for that purpose?
It will be okay if I could make something like I did C# way - make an enum class, list all the components there, and write a constexpr value inside a component class (or somewhere near the enum class, both ways is good for me).
I mean something like that:
/* ComponentsEnum.h */
enum class ComponentsEnum { Comp1, Comp2, Comp3 };
// Here is some magic to generate Components<C1, C2, C3> metaclass.
/* another file */
#include "ComponentsEnum.h"
struct C1 { const ComponentsEnum MyValue = ComponentsEnum::Comp1; };
or something like that
/* ComponentsEnum.h */
enum class ComponentsEnum { Comp1, Comp2, Comp3 };
// Here is all the magic
// All enum members concats into `Components<Comp1, Comp2, Comp3, ...>`
ConcatAll<ComponentsEnum>();
/* another file */
#include "ComponentsEnum.h"
struct Comp1 { };
or maybe something with macro magic:
/* ComponentsEnum.h */
enum class ComponentsEnum { Comp1, Comp2, Comp3 };
#define InitMeta(ComponentsEnumMember) /* Some Magic */
/* another file */
#include "ComponentsEnum.h"
struct Comp1 { InitMeta(ComponentsEnum::Comp1) };
Thanks in advance!
Following on my comment.
You could do something like this in C++17:
// In register.hpp
int register_me();
// In register.cpp
int register_me(){
static int id = 0;
return id++;
}
// In wherever.hpp
// #include "register.hpp"
struct component{
inline static int id = register_me();
};
Pre-C++17 requires moving the definition and initialization to a .cpp for each component::id.
But I strongly recommend not to use this. Rethink your design, converting types to IDs is a code smell for me. C++ is not really designed to do such things, it can haunt you later.
The code above relies on dynamic initialization of all static variable at the start of the program. The order is unspecified, each compilation might result in assignment of different IDs.
Definitely do not put this into any shared libraries before being 100% sure you know how the compilation, linking, and loading processes work for your toolchain because these are outside the scope of C++ Standard.
Thanks to the #JerryJeremiah link and #Quimby advice, I found the solution.
So, I was misled by my C# habits and the idea was quite simple but tricky.
According to the difference between C# generics and C++ templates, generics are runtime instanced types, but templates are compile-time types. So, I do not need to create a map or process the whole codebase, all I need will be generated with templates in compile time.
The solution itself:
I want an enum to generate continuous uid numbers for my components. So, define it:
enum class ComponentEnum
{
C1,
C2,
C3
};
I want a simple interface for my Components to ask for meta information. Define it too:
struct Components
{
template<typename T>
static bool isComponent() { /* Some stuff here */ }
template<typename T>
static int getComponentUID() { /* Some stuff here */ }
};
Now I can ask uid with one simple generalized call Components::getComponentUID<MyComponent>(). Nice.
The real magic. I've created template metaclass and macro to create a typedef and some additional methods:
template <typename T, ComponentEnum enumMember>
struct ComponentMeta
{
static constexpr bool isComponent = true;
static constexpr int uid = static_cast<int>(enumMember);
};
#define ComponentMetaMacro(type_name, enum_name) typedef ComponentMeta<type_name, ComponentEnum::enum_name> Meta; \
static const char* toString() { return #type_name; }
So I can fill methods from my interface with simple forwarding to that metaclass:
struct Components
{
template<typename T>
static bool isComponent() { return T::Meta::isComponent; }
template<typename T>
static int getComponentUID() { return T::Meta::uid; }
};
All things left is include header with metaclass and macro and call the macro:
struct C1
{
ComponentMetaMacro(C1, C1)
};
struct C2
{
ComponentMetaMacro(C2, C2)
};
Run a few tests:
std::cout << C1::toString() << ": " << Components::getComponentUID<C1>() << std::endl;
std::cout << C2::toString() << ": " << Components::getComponentUID<C2>() << std::endl;
C1: 0
C2: 1
Yay!
This solution has three main problems:
isComponent() becomes the static assert instead of the flag. I mean, the code won't compile if T-type is not a component. It is quite ok but smells.
It is a single linked meta. I can't get a component type from the index, only an index from the type. But for serialization purposes, it could be useful to have a backlink.
I should include the enum class to every component header. It means there will be a huge compile-time affect when I will add a new enum member. I suppose there is a way to avoid it but can't see one. The only enum class purpose is to have the smallest index as possible for every component that will be static between compilations. Maybe I have to think about some data generation or another approaches, but for the small project it is ok.

What's the modern C++ way to cast absolute addresses to pointer variables?

In the embedded world for ages people wrote hardware(-configuration)-register-mappings as structures, a really simple example for a 32-bit hardware:
#define hw_baseaddr ((uintptr_t) 0x10000000)
struct regs {
uint32_t reg1;
uint32_t reg2;
};
#define hw_reg ((volatile struct regs *) hw_baseaddr)
void f(void)
{
hw_reg->reg1 = 0xdeadcafe;
hw_reg->reg2 = 0xc0fefe;
}
This works very well, the compiler (gcc at least on our platform) recognizes that the hw_reg is referencing the same address (which is known and constant at compile-time) and is ld'ing it only once. The second st (store) is done with a 4-byte-offset with a single instruction - again on our platform.
How to reproduce this behavior with modern C++ (post C++11) without using #defines?
We tried a lot of things: static const inside and outside classes and constexpr. They both don't like (implicit) reinterprest_cast<>'s .
Responding to a comment as to why changing it: I'm afraid it's mostly fame and glory. But not only. With this C code debugging can be hard. Imagine you'd want to log all write-accesses, this approach would require you to rewrite everything everywhere. However, here I'm not looking for a solution which will simplify a specific situation, I'm looking for inspiration.
EDIT Just to clarify as per some comments: I'm asking this question not to change any code which is working (and was written in the 1990s). I'm looking for a solution for future projects, because I'm not totally happy with the define-implementation, and was asking myself whether modern C++ has a superior possibility.
I think variable templates make for an elegant solution here.
// Include this in some common header
template <class Impl>
volatile Impl& regs = *reinterpret_cast<volatile Impl*>(Impl::base_address);
template <std::uintptr_t BaseAddress>
struct HardwareAt {
static const std::uintptr_t base_address = BaseAddress;
// can't be instantiated
~HardwareAt() = delete;
};
// This goes in a certain HW module's header
struct MyHW : HardwareAt<0x10000000> {
std::uint32_t in;
std::uint32_t out;
};
// Example usage
int main()
{
std::printf("%p\n%p\n", &regs<MyHW>.in, &regs<MyHW>.out);
// or with alias for backward compatibility:
auto hw_reg = &regs<MyHW>;
std::printf("%p\n%p\n", &hw_reg->in, &hw_reg->out);
}
One benefit of using it like this instead of with macros, is that you're type safe, and you can actually refer to registers of different hardware modules from the same source file without mixing it all up.
Since the sole purpose of the #define is to give you access to struct members, you could use a template to do the equivalent. My compiler generates code for the template that is identical to the #define.
// #define hw_reg ((volatile struct regs *) hw_baseaddr)
template <class T, uintptr_t addr>
class RegsPtr
{
public:
RegsPtr() { ; }
volatile T* operator->() const { return reinterpret_cast<T*>(addr); }
volatile T& operator*() const { return *operator->(); }
};
const RegsPtr<struct regs, hw_baseaddr> hw_reg;

C++ : nameable objects belonging to an instance of a class, and stored in it

I am trying to make it possible for a programmer (who uses my library) to create nameable instances of type X that are stored inside an instance of class C (or at least are exclusive to that instance).
These are the only two (ugly) solutions I have managed to come up with (needless to say, I am just picking up C++)
1)
class C
{
public:
class XofC
{
public:
XofC() = delete;
XofC(C& mom)
{
mom.Xlist.emplace_front();
ref = Xlist.front();
}
X& access()
{
return ref;
}
private:
X& ref;
};
//etc
private:
std::forward_list<X> Xlist;
friend class XofC;
//etc
}
Problem:
Having to pass everywhere XofC instances.
2)
class C
{
public:
void newX(std::string);
X& getX(std::string);
//etc.
private:
/*possible run-time mapping implementation
std::vector<X> Xvec;
std::unordered_map<std::string, decltype(Xvec.size())> NameMap;
*/
//etc
}
Problem:
This does the job, but since all names of X (std::string) are known at compilation, the overhead of using run-time std::unordered_map<std::string, decltype(Xvec.size())> kind-of bugs me for something this simple.
Possible(?) solution: compile-time replacing of std::string with automatic index (int). Then I could use:
class C
{
public:
void newX(int); //int: unique index calculated at compile time from std::string
X& getX(int); //int: unique index calculated at compile time from std::string
//etc.
private:
std::vector<X> Xvec;
}
Questions:
Is there a 3)?
Is a compile time solution possible for 2)?
This is the real-life situation: I was starting my first C++ "project" and I thought I could use the practice and utility from an awesome user-friendly, simple and fast argument management library. I plan to make an ArgMan class which can parse the argV based on some specified switches. Switches would be named by the programmer descriptively and the trigger strings be specified (e.g. a switch named recurse could have "-r" and "-recursive" as triggers). When necessary, you should be easily able to get the setting of the switch. Implementation detail: ArgMan would have a std::unordered_map<std::string/*a trigger*/, ??/*something linking to the switch to set on*/>. This ensures an almost linear parse of argV relative to argC. How should I approach this?
You could 'abuse' non-type template arguments to get compiletime named instances:
Live on Coliru
Assume we have a data class X:
#include <string>
struct X
{
int has_some_properties;
std::string data;
};
Now, for our named instances, we define some name constants. The trick is, to give them external linkage, so we can use the address as a non-type template argument.
// define some character arrays **with external linkage**
namespace Names
{
extern const char Vanilla[] = "Vanilla";
extern const char Banana [] = "Banana";
extern const char Coconut[] = "Coconut";
extern const char Shoarma[] = "Shoarma";
}
Now, we make a NamedX wrapper that takes a const char* non-type template argument. The wrapper holds a static instance of X (the value).
// now we can "adorn" a `namedX` with the name constants (above)
template <const char* Name>
struct NamedX
{
static X value;
};
template <const char* Name> X NamedX<Name>::value;
Now you can use it like this:
int main()
{
X& vanilla = NamedX<Names::Vanilla>::value;
vanilla = { 42, "Woot!" };
return vanilla.has_some_properties;
}
Note that due to the fact that the template arguments are addresses, no actual string comparison is done. You cannot, e.g. use
X& vanilla = NamedX<"Vanilla">::value;
becuase "Vanilla" is a prvalue without external linkage. So, in fact you could do without some of the complexity and use tag structs instead: Live on Coliru
While Neil's solution did what I asked for, it was too gimmicky to use in my library. Also, sehe's trick is surely useful, but, if I understood correctly, but doesn't seem related to my question. I have decided to emulate the desired behavior using method 1), here is a less broken attempt at it:
class C
{
private:
class X
{
//std::string member;
//etc
};
public:
class XofC
{
public:
XofC(C & _mom) : mom(_mom)
{
mom.Xlist.emplace_front();
tehX = &(Xlist.front());
}
X & get(maybe)
{
if (&maybe != &mom) throw std::/*etc*/;
return &tehX;
}
private:
X * tehX;
C & mom;
};
private:
//etc
std::forward_list<X> Xlist;
friend class XofC;
//etc
};
Usage:
C foo;
bar = C::XofC(foo); //acts like an instance of X, but stored in C, but you have to use:
bar.get(foo)/*reference to the actual X*/.member = "_1_";
Of course, the downside is you have to make sure you pass bar everywhere you need it, but works decently.
This is how it looks like in my tiny argument manager library:
https://raw.github.com/vuplea/arg_manager.h/master/arg_manager.h

Dealing with C library anonymous struct types in C++

We have a big, old C++ application with a lot of legacy code and a few external libraries written in C. These libraries are very rarely updated - only if we find a bug and the vendor supplies a patch. This happened last week with one library, and upon integrating the new version we found out that if we don't modify the library locally (which we apparently did with the last version) our build breaks with this error message:
non-local function ‘static E* MyCls::myFct(<anonymous struct>*)’ uses anonymous type
This is due to the library declaring a number of handle types like this:
#define _Opaque struct {unsigned long x;} *
typedef _Opaque Handle;
typedef _Opaque Request;
which we use on our side in some classes' function signatures:
class MyCls {
public:
static void* myFct(Handle handle);
...
}
This produces the error above because the compiler can't create a proper name-mangled name for the function(s) as the _Opaque struct has no name.
Our current workaround for this is to patch the library header file, explicitly giving the struct a name:
//#define _Opaque struct {unsigned long x;} * //Replaced by typedef below!
typedef struct __Opaque {unsigned long x;} * _Opaque;
This is obviously bad because we don't want to touch the library if possible. Another even worse option would be to convert the types to void* in all function signatures and cast them back to their respective types. And there's the worst option to rewrite every affected function in pure C...
So, my question is: Is there any better option than patching the library? Is there an easy solution I am overlooking? What would be the best way to solve this?
You can accomplish this with a minimal change to the #define line, exploiting the rule in 7.1.3:8 that the first typedef-name declared by the declaration to be
that class type (or enum type) is used to denote the class type (or enum type) for linkage purposes only:
#define MAKE_DUMMY2(line) dummy_ ## line
#define MAKE_DUMMY(line) MAKE_DUMMY2(line)
#define _Opaque struct {unsigned long x;} MAKE_DUMMY(__LINE__), *
This gives Handle and Request etc. minimal linkage.
You can introduce names by declaring new types, which simply contain these elements. Use those types for your parameters.
namespace MON {
struct t_handle {
Handle handle;
};
class MyCls {
public:
static void* myFct(t_handle handle);
...
};
}
If you're willing to modify your methods on the interface, you can do slightly better than void *:
struct CHandle {
void *p;
CHandle(void *p): p(p) { }
};
struct CRequest {
void *p;
CRequest(void *p): p(p) { }
};
static CHandle make(Handle handle) { return CHandle(handle); }
static Handle get(CHandle handle) { return static_cast<Handle>(handle.p); }
static CRequest make(Request request) { return CRequest(request); }
static Request get(CRequest request) { return static_cast<Request>(request.p); }
Here, CHandle and CRequest have linkage and so can be used in your method signatures; the overloads of make and get have internal linkage and so can interface with the anonymous types. You can put this in a header, even the static functions.
You'll have to modify your code so that when e.g. MyCls::myFct calls into the library, you wrap parameters with get and return values with make.
This seems to work:
class MyCls {
public:
typedef _Opaque MHandle;
static void* myFct(MHandle handle) {
return 0;
}
};