Related
I have a template class which has a lot of variables, all of the same type
template<typename T>
struct Location
{
T lat;
T lon;
T alt;
// and roughly 20 variables more of type T
};
In my code T is either float or double, depending on the precision I need. Sometimes I need to cast between these two struct. Thus I want to define a conversion operator
template<typename A, typename B> operator Location<B> {
Location<B> ret;
// cast every variable in *this from type A to type B
return ret;
}
Since there are a lot of variables in Location and it is very likely that I will need to add more variables to the struct in future, I do not want to write each cast by hand in my conversion operator.
Thus, I want to know whether there is some automagically way to cast all variables in the struct?
I'm afraid there's not such a way. I would probably write templated copy constructor and assign each variable manually. You'll do it just once now, and then everytime you add a new variable - it's not a big deal IMO.
You cannot do that natively.
one function that you can write, which might be useful in another contexts (such as comparison) is a tie/as_tuple method:
template<typename T>
struct Location
{
T lat;
T lon;
T alt;
// and roughly 20 variables more of type T
auto as_tuple() const { return std::tie(lat, lon, alt /*, ..*/); }
template <typename T2> operator Location<T2>() const
{
return std::make_from_tuple<Location<T2>>(as_tuple());
// return std::apply([](auto... args){ return Location<T2>{static_cast<T2>(args)...}; },
// as_tuple());
}
};
Personally i never had this usecase, but if all entries in that struct are of the same type shouldn't something like the following work?
template<typename T>
struct Location {
T a;
T b;
T c;
template<typename B> operator Location<B>() {
if constexpr(std::is_same_v<T,B>) {
return *this;
}
Location<B> ret;
constexpr std::size_t count = sizeof(Location<T>)/sizeof(T);
static_assert(sizeof(Location<B>)==sizeof(B)*count);
for (std::size_t i=0;i<count;++i){
B b;
T a;
memcpy(&a, ((char*)this)+i*sizeof(T), sizeof(T));
b = static_cast<B>(a);
memcpy(((char*)&ret) + i*sizeof(B), &b, sizeof(B));
}
return ret;
}
};
I'm quite sure that somewhere in that monstrosity is UB or at least issues with memory alignment.
This obviously won't work with pointers or types/structs which contain pointers.
There is no good way to do this... but here is a completely terrible way that should never be used and works only if Location contains only T instances. There may also be alignment issues.
template<typename B>
operator Location<B>() const {
Location<B> ret;
for (int i = 0; i <= (sizeof(Location<T>) / sizeof(T)); i++) {
*(&ret.lat + i) = B(*(&lat + i));
}
return ret;
}
Let have a type T and a struct having ONLY uniform elements of T type.
struct Foo {
T one,
T two,
T three
};
I'd like to access them in fallowing way:
struct Foo {
T one,
T two,
T three
T &operator [] (int i)
{
return *(T*)((size_t)this + i * cpp_offsetof(Foo, two));
}
};
where cpp_offsetof macro (it is considered to be correct) is:
#define cpp_offsetof(s, m) (((size_t)&reinterpret_cast<const volatile char&>((((s*)(char*)8)->m))) - 8)
The C++ standard doesn't guarantee it, but can we assume that members are distanced by a fixed offset and above is correct, cross-platform solution?
100% compatible solution would be:
struct Foo {
T one,
T two,
T three
T &operator [] (int i) {
const size_t offsets[] = { cpp_offsetof(Foo, one), cpp_offsetof(Foo, two), cpp_offsetof(Foo, three) };
return *(T*)((size_t)this + offsets[i]);
}
};
[edit]standard, compliant and faster version was presented by snk_kid using pointers to data members[/edit]
but it requires extra lookup table which I'm trying to avoid.
//EDIT
And one more. I cannot use just an array and constants to index these fields, they have to be named fields of a struct (some macro requires that).
//EDIT2
Why those have to be named fields of a struct? What is the macro? It is settings system of a bigger project. Simplifying it's sth like this:
struct Foo {
int one;
int two;
}
foo;
struct Setting { void *obj, size_t filed_offset, const char *name, FieldType type }
#define SETTING(CLASS, OBJ, FIELD, TYPE) { OBJ, cpp_offsetof(CLASS, FIELD), #OBJ #FIELD, TYPE }
Setting settings[] = {
SETTING(Foo, foo, one, INT_FIELD),
SETTING(Foo, foo, two, INT_FIELD)
};
And once again: I'm not looking form 100% compatible solution but 99%. I'm asking if we can expect that some compilers will put non-uniform padding between uniform fields.
Your code doesn't work with NON-POD types such those which using virtual member functions. There is a standard compliant (and efficient) way to achieve what you're trying to do, using pointer to data members:
template< typename T >
struct Foo {
typedef size_t size_type;
private:
typedef T Foo<T>::* const vec[3];
static const vec v;
public:
T one;
T two;
T three;
const T& operator[](size_type i) const {
return this->*v[i];
}
T& operator[](size_type i) {
return this->*v[i];
}
};
template< typename T >
const typename Foo<T>::vec Foo<T>::v = { &Foo<T>::one, &Foo<T>::two, &Foo<T>::three };
Just make sure you use const every with the table of pointer to data-members to get optimizations. Check here to see what I'm talking about.
Another way is with template specialization if what you are trying to achieve is still a compile time feature.
class Foo {
T one;
T two;
T three;
};
template <int i> T & get(Foo& foo);
template T& get<1>(Foo& foo){ return foo.one;}
template T& get<2>(Foo& foo){ return foo.two;}
template T& get<3>(Foo& foo){ return foo.three;}
It would be nice to define get as a member function but you cannot
specialize template member functions. Now if this is only a compile time
expansion you are looking for then this will avoid the lookup table
issue of one of the previous posts. If you need runtime resolution
then you need a lookup table obviously.
--
Brad Phelan
http://xtargets.heroku.com
You might be able to achieve what you want using an array to hold the data (so you can get indexed access without using a lookup table) and having references to the various array elements (so you can have 'named' elements for use by your macros).
I'm not sure what your macros require, so I'm not 100% sure this will work, but it might. Also, I'm not sure that the slight overhead of the lookup table approach is worth jumping through too many hoops to avoid. On the other hand, I don't think the approach I suggest here is any more complex than the table-of-pointers approach, so here it is for your consideration:
#include <stdio.h>
template< typename T >
struct Foo {
private:
T data_[3];
public:
T& one;
T& two;
T& three;
const T& operator[](size_t i) const {
return data_[i];
}
T& operator[](size_t i) {
return data_[i];
}
Foo() :
one( data_[0]),
two( data_[1]),
three( data_[2])
{};
};
int main()
{
Foo<int> foo;
foo[0] = 11;
foo[1] = 22;
foo[2] = 33;
printf( "%d, %d, %d\n", foo.one, foo.two, foo.three);
Foo<int> const cfoo( foo);
printf( "%d, %d, %d\n", cfoo[0], cfoo[1], cfoo[2]);
return 0;
}
You can't because the compiler can add dead bytes between members to allow padding.
There is two ways to do what you want.
The first is to use your compiler-specific keyword or pragma macro that will force the compiler to not add padding bytes. But that is not portable.
That said it might be the easiest way to do it with your macro requirements, so I suggest you explore this possibility and prepare for adding more pragma when using different compilers.
The other way is to first make sure your members are aligned, then add accessors :
struct Foo {
T members[ 3 ]; // arrays are guarrantied to be contigu
T& one() { return members[0]; }
const T& one() const { return members[0]; }
//etc...
};
If you're sure the compilers you're using are going to generate the right code for this (and I'd imagine they would, assuming T isn't a reference type anyway) the best thing to do is put in some kind of check that the struct is laid out as you think. I can't think of any particular reason to insert non-uniform padding between adjacent members of the same type, but if you check the struct layout by hand then you'll at least know if it happens.
If the struct (S) has exactly N members of type T, for example, you can check at compile time that they are tightly packed simply using sizeof:
struct S {
T a,b,c;
};
extern const char check_S_size[sizeof(S)==3*sizeof(T)?1:-1];
If this compiles, then they're tightly packed, as there's no space for anything else.
If you just happen to have N members, that you want to ensure are placed directly one after the other, you can do something similar using offsetof:
class S {
char x;
T a,b,c;
};
extern const char check_b_offset[offsetof(S,b)==offsetof(S,a)+sizeof(T)?1:-1];
extern const char check_c_offset[offsetof(S,c)==offsetof(S,b)+sizeof(T)?1:-1];
Depending on the compiler, this might have to become a runtime check, possibly not using offsetof -- which you might want to do for non-POD types anyway, because offsetof isn't defined for them.
S tmp;
assert(&tmp.b==&tmp.a+1);
assert(&tmp.c==&tmp.b+1);
This doesn't say anything about what to do if the asserts start failing, but you should at least get some warning that the assumptions aren't true...
(By the way, insert appropriate casts to char references and so on where appropriate. I left them out for brevity.)
I've recently run into a quite a few situations where the Named Parameter Idiom would be useful, but I'd like it to be guaranteed in compile-time. The standard method of returning references in a chain almost always appears to invoke a run-time constructor (compiling with Clang 3.3 -O3).
I haven't been able to find anything with reference to this so I tried to get this to work with constexpr and got something functional:
class Foo
{
private:
int _a;
int _b;
public:
constexpr Foo()
: _a(0), _b(0)
{}
constexpr Foo(int a, int b)
: _a(a), _b(b)
{}
constexpr Foo(const Foo & other)
: _a(other._a), _b(other._b)
{}
constexpr Foo SetA(const int a) { return Foo(a, _b); }
constexpr Foo SetB(const int b) { return Foo(_a, b); }
};
...
Foo someInstance = Foo().SetB(5).SetA(2); //works
While this is okay for a small number of parameters, for larger numbers it quickly blows up into a mess:
//Unlike Foo, Bar takes 4 parameters...
constexpr Bar SetA(const int a) { return Bar(a, _b, _c, _d); }
constexpr Bar SetB(const int b) { return Bar(_a, b, _c, _d); }
constexpr Bar SetC(const int c) { return Bar(_a, _b, c, _d); }
constexpr Bar SetD(const int d) { return Bar(_a, _b, _c, d); }
Is there a better way? I'm looking at doing this with classes that have many (30+) parameters and this seems like it would be prone to error if extended in the future.
EDIT: Removed C++1y tag -- while C++1y does appear to fix the problem (thanks TemplateRex!) this is for production code, and we are stuck with C++11. If that means its impossible, then I guess that's just the way it is.
EDIT2: To show why I'm looking for this, here's a use case. Currently with our platform, developers need to explicitly set bit vectors for hardware configurations, and while this is okay it's very error prone. Some are using designated initializers from the C99 extension, which is okay but non-standard:
HardwareConfiguration hardwareConfig = {
.portA = HardwareConfiguration::Default,
.portB = 0x55,
...
};
Most, however, aren't even using this, and are just inputting a blob of numbers. So as a working improvement, I'd like to move towards something like this (since it also forces better code):
HardwareConfiguration hardwareConfig = HardwareConfiguration()
.SetPortA( Port().SetPolarity(Polarity::ActiveHigh) )
.SetPortB( Port().SetPolarity(Polarity::ActiveLow) );
Which might be far more verbose, but much clearer when reading later.
Using Template Metaprogramming
Here is something I came up with to solve your problem (at least partially). By using template metaprogramming, you can leverage the compiler to do most of the job for you. These techniques look weird for those who have never seen such code before, but thankfully most of the complexity can be hidden away in a header and the users only interact with the library in a neat and terse manner.
A Sample Class Definition and its Use
Here is an example of what defining a class would entail on your part:
template <
//Declare your fields here, with types and default values
typename PortNumber = field<int, 100>,
typename PortLetter = field<char, 'A'>
>
struct MyStruct : public const_obj<MyStruct, PortNumber, PortLetter> //Derive from const_obj like this, passing the name of your class + all field names as parameters
{
//Your setters have to be declared like this, by calling the Set<> template provided by the base class
//The compiler needs to be told that Set is part of MyStruct, probably because const_obj has not been instantiated at this point
//in the parsing so it doesn't know what members it has. The result is that you have to use the weird 'typename MyStruct::template Set<>' syntax
//You need to provide the 0-based index of the field that holds the corresponding value
template<int portNumber>
using SetPortNumber = typename MyStruct::template Set<0, portNumber>;
template<int portLetter>
using SetPortLetter = typename MyStruct::template Set<1, portLetter>;
template<int portNumber, char portLetter>
using SetPort = typename MyStruct::template Set<0, portNumber>
::MyStruct::template Set<1, portLetter>;
//You getters, if you want them, can be declared like this
constexpr int GetPortNumber() const
{
return MyStruct::template Get<0>();
}
constexpr char GetPortLetter() const
{
return MyStruct::template Get<1>();
}
};
Using the Class
int main()
{
//Compile-time generation of the type
constexpr auto myObject =
MyStruct<>
::SetPortNumber<150>
::SetPortLetter<'Z'>();
cout << myObject.GetPortNumber() << endl;
cout << myObject.GetPortLetter() << endl;
}
Most of the job is done by the const_obj template. It provides a mechanism to modify your object at compile time. Much like a Tuple, the fields are accessed with 0-based indices but this does not stop you from wrapping the setters with friendly names, as is done with SetPortNumber and SetPortLetter above. (They just forward to Set<0> and Set<1>)
About Storage
In the current implementation, after all the setters have been called and the object declared, the fields end up being stored in a compact array of const unsigned char's named data in the base class. If you use fields that are not unsigned chars (as in done above with PortNumber for example) the field is divided in big endien unsigned char's (could be changed to little endien as needed). If you don't need an actual storage that has an actual memory address, you could omit it altogether by modifying the packed_storage (see full implementation link below) and the values would still be accessible at compile time.
Limitations
This implementation only allows integral types to be used as fields (all flavors of shorts, ints, longs, bool, char). You can still provide setters that act on more than one field though. Example:
template<int portNumber, char portLetter>
using SetPort = typename MyStruct::template Set<0, portNumber>::
MyStruct::template Set<1, portLetter>;
Full Code
The full code for the implementation of this little library can be found here:
Full Implementation
Additional Notes
This code has been tested and works with the C++11 implementation of both g++ and clang.
It has not been tested for hours and hours so of course there may be bugs but it should provide you with a good base to start with. I hope this helps!
In C++14, constraints on constexpr function will be relaxed, and the usual chaining of reference-returning setters will work at compile-time:
#include <iostream>
#include <iterator>
#include <array>
#include <utility>
class Foo
{
private:
int a_ = 0;
int b_ = 0;
int c_ = 0;
int d_ = 0;
public:
constexpr Foo() = default;
constexpr Foo(int a, int b, int c, int d)
:
a_{a}, b_{b}, c_{c}, d_{d}
{}
constexpr Foo& SetA(int i) { a_ = i; return *this; }
constexpr Foo& SetB(int i) { b_ = i; return *this; }
constexpr Foo& SetC(int i) { c_ = i; return *this; }
constexpr Foo& SetD(int i) { d_ = i; return *this; }
friend std::ostream& operator<<(std::ostream& os, const Foo& f)
{
return os << f.a_ << " " << f.b_ << " " << f.c_ << " " << f.d_ << " ";
}
};
int main()
{
constexpr Foo f = Foo{}.SetB(5).SetA(2);
std::cout << f;
}
Live Example using Clang 3.4 SVN trunk with std=c++1y.
I'm not sure if classes with 30 parameters are a good idea (Single Responsiblity Principle and all that) but at least the above code scales linearly in the number of setters, with only 1 argument per setter. Note also that there are only 2 constructors: the default one (which takes its arguments from the in-class initializers) and the full one which takes 30 ints in your ultimate case).
I'm refactoring a class for my project to adapt int data. The code is quite complicated, try to give a simple example below:
struct A {
A(int a):a_(a) {} // Supports implicit conversion from int
int a_;
};
void print(A a) { cout<<a.a_<<endl; }
void x2(A *a) { // change a's value
a->a_ *= 2;
}
int main() {
int b = 2;
print(b); // pass int as A without any problem
x2(&b); // pass int* as A* - failed
cout<<b<<endl; // b is supposed to changed by x2()
}
In this case maybe template is a good choice, but I'm afraid rewritting the whole class with template would be a huge effort and would do a little harm to the readablity especially for my colleagues.
Is there any other way to use "int*" as "A*"?
No, there's no "way". What you are trying to do here is violating the contract on x2, which is that a will be a valid pointer to A.
The simplest change to it would be to change x2 to:
(There's really no need to use a pointer here)
void x2 (A& a) {
a.a_ *= 2;
}
And then call it with A value that's wrapped around the int (like #jrok suggested):
A a(2);
x2(a);
If you are conderned with printing, provide operator<< for A.
Let have a type T and a struct having ONLY uniform elements of T type.
struct Foo {
T one,
T two,
T three
};
I'd like to access them in fallowing way:
struct Foo {
T one,
T two,
T three
T &operator [] (int i)
{
return *(T*)((size_t)this + i * cpp_offsetof(Foo, two));
}
};
where cpp_offsetof macro (it is considered to be correct) is:
#define cpp_offsetof(s, m) (((size_t)&reinterpret_cast<const volatile char&>((((s*)(char*)8)->m))) - 8)
The C++ standard doesn't guarantee it, but can we assume that members are distanced by a fixed offset and above is correct, cross-platform solution?
100% compatible solution would be:
struct Foo {
T one,
T two,
T three
T &operator [] (int i) {
const size_t offsets[] = { cpp_offsetof(Foo, one), cpp_offsetof(Foo, two), cpp_offsetof(Foo, three) };
return *(T*)((size_t)this + offsets[i]);
}
};
[edit]standard, compliant and faster version was presented by snk_kid using pointers to data members[/edit]
but it requires extra lookup table which I'm trying to avoid.
//EDIT
And one more. I cannot use just an array and constants to index these fields, they have to be named fields of a struct (some macro requires that).
//EDIT2
Why those have to be named fields of a struct? What is the macro? It is settings system of a bigger project. Simplifying it's sth like this:
struct Foo {
int one;
int two;
}
foo;
struct Setting { void *obj, size_t filed_offset, const char *name, FieldType type }
#define SETTING(CLASS, OBJ, FIELD, TYPE) { OBJ, cpp_offsetof(CLASS, FIELD), #OBJ #FIELD, TYPE }
Setting settings[] = {
SETTING(Foo, foo, one, INT_FIELD),
SETTING(Foo, foo, two, INT_FIELD)
};
And once again: I'm not looking form 100% compatible solution but 99%. I'm asking if we can expect that some compilers will put non-uniform padding between uniform fields.
Your code doesn't work with NON-POD types such those which using virtual member functions. There is a standard compliant (and efficient) way to achieve what you're trying to do, using pointer to data members:
template< typename T >
struct Foo {
typedef size_t size_type;
private:
typedef T Foo<T>::* const vec[3];
static const vec v;
public:
T one;
T two;
T three;
const T& operator[](size_type i) const {
return this->*v[i];
}
T& operator[](size_type i) {
return this->*v[i];
}
};
template< typename T >
const typename Foo<T>::vec Foo<T>::v = { &Foo<T>::one, &Foo<T>::two, &Foo<T>::three };
Just make sure you use const every with the table of pointer to data-members to get optimizations. Check here to see what I'm talking about.
Another way is with template specialization if what you are trying to achieve is still a compile time feature.
class Foo {
T one;
T two;
T three;
};
template <int i> T & get(Foo& foo);
template T& get<1>(Foo& foo){ return foo.one;}
template T& get<2>(Foo& foo){ return foo.two;}
template T& get<3>(Foo& foo){ return foo.three;}
It would be nice to define get as a member function but you cannot
specialize template member functions. Now if this is only a compile time
expansion you are looking for then this will avoid the lookup table
issue of one of the previous posts. If you need runtime resolution
then you need a lookup table obviously.
--
Brad Phelan
http://xtargets.heroku.com
You might be able to achieve what you want using an array to hold the data (so you can get indexed access without using a lookup table) and having references to the various array elements (so you can have 'named' elements for use by your macros).
I'm not sure what your macros require, so I'm not 100% sure this will work, but it might. Also, I'm not sure that the slight overhead of the lookup table approach is worth jumping through too many hoops to avoid. On the other hand, I don't think the approach I suggest here is any more complex than the table-of-pointers approach, so here it is for your consideration:
#include <stdio.h>
template< typename T >
struct Foo {
private:
T data_[3];
public:
T& one;
T& two;
T& three;
const T& operator[](size_t i) const {
return data_[i];
}
T& operator[](size_t i) {
return data_[i];
}
Foo() :
one( data_[0]),
two( data_[1]),
three( data_[2])
{};
};
int main()
{
Foo<int> foo;
foo[0] = 11;
foo[1] = 22;
foo[2] = 33;
printf( "%d, %d, %d\n", foo.one, foo.two, foo.three);
Foo<int> const cfoo( foo);
printf( "%d, %d, %d\n", cfoo[0], cfoo[1], cfoo[2]);
return 0;
}
You can't because the compiler can add dead bytes between members to allow padding.
There is two ways to do what you want.
The first is to use your compiler-specific keyword or pragma macro that will force the compiler to not add padding bytes. But that is not portable.
That said it might be the easiest way to do it with your macro requirements, so I suggest you explore this possibility and prepare for adding more pragma when using different compilers.
The other way is to first make sure your members are aligned, then add accessors :
struct Foo {
T members[ 3 ]; // arrays are guarrantied to be contigu
T& one() { return members[0]; }
const T& one() const { return members[0]; }
//etc...
};
If you're sure the compilers you're using are going to generate the right code for this (and I'd imagine they would, assuming T isn't a reference type anyway) the best thing to do is put in some kind of check that the struct is laid out as you think. I can't think of any particular reason to insert non-uniform padding between adjacent members of the same type, but if you check the struct layout by hand then you'll at least know if it happens.
If the struct (S) has exactly N members of type T, for example, you can check at compile time that they are tightly packed simply using sizeof:
struct S {
T a,b,c;
};
extern const char check_S_size[sizeof(S)==3*sizeof(T)?1:-1];
If this compiles, then they're tightly packed, as there's no space for anything else.
If you just happen to have N members, that you want to ensure are placed directly one after the other, you can do something similar using offsetof:
class S {
char x;
T a,b,c;
};
extern const char check_b_offset[offsetof(S,b)==offsetof(S,a)+sizeof(T)?1:-1];
extern const char check_c_offset[offsetof(S,c)==offsetof(S,b)+sizeof(T)?1:-1];
Depending on the compiler, this might have to become a runtime check, possibly not using offsetof -- which you might want to do for non-POD types anyway, because offsetof isn't defined for them.
S tmp;
assert(&tmp.b==&tmp.a+1);
assert(&tmp.c==&tmp.b+1);
This doesn't say anything about what to do if the asserts start failing, but you should at least get some warning that the assumptions aren't true...
(By the way, insert appropriate casts to char references and so on where appropriate. I left them out for brevity.)