I have a couple of strong types that are just aliases of a class template that contains useful shared code.
template <typename T>
struct DiscretePosition {
public:
int x{0};
int y{0};
// ... useful generic functions
};
struct ChunkTag{};
struct TileTag{};
using ChunkPosition = DiscretePosition<ChunkTag>;
using TilePosition = DiscretePosition<TileTag>;
I would like to write a constructor or helper function to help me convert one of these types to the other.
TilePosition tilePosition{1, 1};
ChunkPosition chunkPosition{tilePosition};
// or
ChunkPosition chunkPosition{tilePosition.asChunkPosition()};
This constructor would just take the underlying x, y and scale them to match the other type using a constant.
Is there a way to do this, or would I need to use a free function?
Here is one possible generic solution that allows you to specialize a get_scaling_factor function for conversions you want to allow:
godbolt link
#include <iostream>
struct ChunkTag{};
struct TileTag{};
template<typename T, typename U>
consteval double get_scaling_factor();
template<>
consteval double get_scaling_factor<ChunkTag, TileTag>() {
return 2;
}
template <typename T>
struct DiscretePosition {
public:
int x{0};
int y{0};
// ... useful generic functions
DiscretePosition(int x, int y) : x(x), y(y) {}
template<typename U>
explicit DiscretePosition(const DiscretePosition<U>& other)
: x(other.x * get_scaling_factor<T, U>())
, y(other.y * get_scaling_factor<T, U>())
{}
};
using ChunkPosition = DiscretePosition<ChunkTag>;
using TilePosition = DiscretePosition<TileTag>;
int main() {
TilePosition tilePosition{1, 1};
ChunkPosition chunkPosition{tilePosition};
std::cout << chunkPosition.x << ", " << chunkPosition.y << std::endl;
// or
// ChunkPosition chunkPosition{tilePosition.asChunkPosition()};
}
The accepted answer worked fine, but I ended up doing something different as a more general-purpose solution.
For each strong type that I wanted to add functionality to, I turned it into a full derived class:
class ChunkPosition : public DiscretePosition<DiscreteImpl::ChunkTag>
{
public:
ChunkPosition();
ChunkPosition(int inX, int inY);
explicit ChunkPosition(const TilePosition& tilePosition);
};
class TilePosition : public DiscretePosition<DiscreteImpl::TileTag>
{
public:
TilePosition();
TilePosition(int inX, int inY);
explicit TilePosition(const ChunkPosition& chunkPosition);
};
Related
I am looking for a convenient to create a C++ class where some member variables are only present if a template flag is set. As a simple example, let's assume I want to toggle an averageSum in an performance sensitive calculation, i.e.
struct Foo {
// Some data and functions..
void operator+=(const Foo& _other) {}
};
template<bool sumAverages>
class Calculator {
public:
// Some member variables...
// Those should only be present if sumAverages is true
int count = 0;
Foo resultSum;
void calculate(/* some arguments */) {
// Calculation of result...
Foo result;
// This should only be calculated if sumAverages is true
++count;
resultSum += result;
// Possibly some post processing...
}
};
One way would be using preprocessor defines, but those are rather inconvenient especially if I need both versions in the same binary. So I am looking for an alternative using templates and if constexpr and something like the following Conditional class:
template<bool active, class T>
struct Conditional;
template<class T>
struct Conditional<true, T> : public T {};
template<class T>
struct Conditional<false, T> {};
My first shot was this:
template<bool sumAverages>
class Calculator {
public:
int count = 0;
Conditional<sumAverages, Foo> resultSum;
void calculate(/* some arguments */) {
Foo result;
if constexpr(sumAverages) {
++count;
resultSum += result;
}
}
};
The if constexpr should incur no run time cost and as it is dependent on a template variable should allow non-compiling code in the false case (e.g. in this example Conditional<false, Foo> does not define a += operator, still it compiles). So this part is more or less perfect. However the variables count and resultSum are still somewhat present. In particular, as one can not derive from a fundamental type, the Conditional class does not allow to toggle the int dependent on the template. Furthermore every Conditional<false, T> variable still occupies one byte possibly bloating small classes. This could be solvable by the new [[no_unique_address]] attribute, however my current compiler chooses to ignore it in all my tests, still using at leas one byte per variable.
To improve things I tried inheriting the variables like this
struct OptionalMembers {
int count;
Foo resultSum;
};
template<bool sumAverages>
class Calculator : public Conditional<sumAverages, OptionalMembers> {
public:
void calculate(/* some arguments */) {
Foo result;
if constexpr(sumAverages) {
++OptionalMembers::count;
OptionalMembers::resultSum += result;
}
}
};
This should come at no space cost as inheriting from am empty class should do literally nothing, right? A possible disadvantage is that one cannot freely set the order of the variables (the inherited variables always come first).
My questions are:
Do you see any problems using the approaches described above?
Are there better options to de(activate) variables like this?
There are a different ways to solve this, one straightforward one would be using template specialization:
#include <iostream>
template <bool b> struct Calculator {
int calculate(int i, int j) { return i + j; }
};
template <> struct Calculator<true> {
int sum;
int calculate(int i, int j) { return sum = i + j; }
};
int main(int argc, char **argv) {
Calculator<false> cx;
cx.calculate(3, 4);
/* std::cout << cx.sum << '\n'; <- will not compile */
Calculator<true> cy;
cy.calculate(3, 4);
std::cout << cy.sum << '\n';
return 0;
}
Another solution would be to use mixin-like types to add features to your calculator type:
#include <iostream>
#include <type_traits>
struct SumMixin {
int sum;
};
template <typename... Mixins> struct Calculator : public Mixins... {
int calculate(int i, int j) {
if constexpr (is_deriving_from<SumMixin>()) {
return SumMixin::sum = i + j;
} else {
return i + j;
}
}
private:
template <typename Mixin> static constexpr bool is_deriving_from() {
return std::disjunction_v<std::is_same<Mixin, Mixins>...>;
}
};
int main(int argc, char **argv) {
Calculator<> cx;
cx.calculate(3, 4);
/* std::cout << cx.sum << '\n'; <- will not compile */
Calculator<SumMixin> cy;
cy.calculate(3, 4);
std::cout << cy.sum << '\n';
return 0;
}
I have lots of code which creates a std::set<Port*>. Now by default this uses less<Port*> which sorts the set on pointer values. This creates problem in our tool. I want to provide a default comparator my_less for all set<Port*> without having to go and change all the code. So I tried template specialization :
namespace std {
template<> class set<Port*> : public set<Port*, my_less> {};
};
I put this code in a header file already included by all the code files. This works the way I expected that all set<Port*> are now using my_less. The problem is that such specialization is not inheriting constructors. So i get an error if I want to do this :
std::set<Port*> myset_new(myset1.begin(), myset1.end());
set.cpp:53:63: error: no matching function for call to
‘std::set<Port*>::set(std::set<Port*, znl_id_less>::iterator, std::set<Port*, my_less>::iterator)’
set_include.h:27:70: note: candidates are: std::set<Port*>::set()
set_include.h:27:70: note: std::set<Port*>::set(const std::set<Port*>&)
What is a good way to solve this (I can copy the code for constructors but that doesn't seem clean).
Is there any other way to achieve what I am trying to do apart from:
template<> class set<Port*> : public set<Port*, my_less> {};
Since C++11, you can inherit constructors easily with the using-declaration, like this:
namespace std {
template<> class set<Port*> : public set<Port*, my_less> {
public: using set<Port*, my_less>::set;
};
};
Here is my generic solutions to this problem
#include <set>
#include <functional>
#include <iostream>
// structs
struct my_struct
{
int a;
int b;
};
struct my_second_struct
{
int a;
int b;
};
bool operator<(const my_second_struct& m1, const my_second_struct& m2)
{
return m1.b < m2.b;
}
// alias helper
template <typename T>
using custom_comparator_t = std::function<bool(const T, const T)>;
// function to proxy already defined operator to pointers
template<typename T>
auto get_pointer_less()
{
return [](const T* v1, const T* v2) -> bool { return (*v1) < (*v2); };
}
// this is generic solution
template<typename T>
using pointer_set = std::set<T*, custom_comparator_t<T*>>;
// and final config
template<typename T>
auto get_pointer_set()
{
return pointer_set<T>( get_pointer_less<T>() );
}
template<typename T, typename _T>
void fill_and_display(_T& s)
{
s.insert(new T{10, 20});
s.insert(new T{20, 10});
s.insert(new T{0, 100});
s.insert(new T{100, 0});
std::cout << "set: ";
for (const T *ms : s)
std::cout << "( " << ms->a << " ; " << ms->b << " )";
std::cout << std::endl;
}
int main()
{
// First option, create custom less operator inline
std::set<my_struct *, custom_comparator_t<my_struct *>> myset(
[](const my_struct *ms1, const my_struct *ms2) { return ms1->a < ms2->a; }
);
fill_and_display<my_struct>(myset);
// Second option, reuse, already defined less operator
std::set<my_second_struct *, custom_comparator_t<my_second_struct*>> my_second_set(
get_pointer_less<my_second_struct>()
);
fill_and_display<my_second_struct>(my_second_set);
// generic colution for second set
auto my_third_set = get_pointer_set<my_second_struct>();
fill_and_display<my_second_struct>(my_third_set);
return 0;
}
In the book that I found there's a code computing a square root of a given number, but the code doesn't compile. There is a lot of errors when instantiating the template. This is the code:
#include <iostream>
template
<int N, int LO=1, int HI=N> class Sqrt {
public:
enum { mid = (LO+HI+1)/2 };
enum { result = (N<mid*mid) ? Sqrt<N,LO,mid-1>::result : Sqrt<N,mid,HI>::result };
};
template<int N, int M> class Sqrt<N,M,M> {
public:
enum { result=M };
};
int main()
{
std::cout << Sqrt<5>::result << std::endl;
}
and many of the warnings are
enumeral mismatch in conditional expression 'Sqrt<5,1,1>::< anonymous enum> vs 'Sqrt<5,2,2>::< anonymous enum>' [-Wenum-compare]
as I tested later this warning is not critical, for example in the code
class a {
public:
enum {test = 0};
};
class b {
public:
enum {test = 1};
};
class c {
public:
enum {test = 2 < 3 ? a::test : b::test};
};
int main()
{
int v = c::test;
}
I get the same warning, but the code compiles. My confusion is caused because if I place the '-Wenum-compare' in compiler options, the first code compiles. What is the real problem here?
Instead of enum, you can use static constexpr int.
template <int N, int LO=1, int HI=N> struct Sqrt {
static constexpr int mid = (LO+HI+1)/2;
static constexpr int result = (N<mid*mid) ? Sqrt<N,LO,mid-1>::result : Sqrt<N,mid,HI>::result;
};
template<int N, int M> struct Sqrt<N,M,M> {
static constexpr int result=M;
};
To get rid of the warning you can cast the enums into their integer values. This means you have two integers instead of two different enumerations.
template
<int N, int LO=1, int HI=N> class Sqrt {
public:
enum { mid = (LO+HI+1)/2 };
enum { result = (N<mid*mid) ? static_cast<int>(Sqrt<N,LO,mid-1>::result) : static_cast<int>(Sqrt<N,mid,HI>::result) };
};
template<int N, int M> class Sqrt<N,M,M> {
public:
enum { result=M };
};
int main()
{
std::cout << Sqrt<5>::result << std::endl;
}
Will compile without warning. As for why you get these warnings even though it compiles see: Why do I get an error when directly comparing two enums?
I have a vector 3D class
class Vector3D{
public: float x; float y; float z;
//some functions, e.g. operator+ - * /
//some 3D-specific function
};
and a vector N-D class.
template<int constSize> class VecFloatFix{
float database[constSize];
//some functions, e.g. operator+ - * /
};
I noticed that there is code-duplication between two classes, so I think I should make Vector3D derived from VecFloatFix<3> :-
class Vector3D : public VecFloatFix<3>{
//some 3D-specific function
};
Everything seems to be good, except that there are a lot of user code access Vector3D::x,y,z directly.
Is it possible to make Vector3D derived from VecFloatFix<3> while not break user's code?
My best guess is around :-
template<int constSize> class VecFloatFix{
union{
float database[constSize];
float x,y,z; ????? sound like a hack
}
//some functions, e.g. operator+ - * /
};
Edit: Hardcoding x,y,z into VecFloatFix is unsustainable.
If I have a new class Vector2D that derived from VecFloatFix<2>, Vector2D::z will compile fine (dangerous).
Here is a version that only exposes x, y, z components for vectors of size 3. Obviously other sizes may also be specialized.
template<int constSize> struct VecFloatStorage
{
float database[constSize];
};
template<> struct VecFloatStorage<3>
{
union
{
float database[3];
struct { float x, y, z; };
};
};
template<int constSize> class VecFloatFix : public VecFloatStorage<constSize>
{
public:
// Methods go here.
};
I don't know if the standard guarantees struct { float x, y, z; } to have the same memory layout as float data[3], however in practice I am pretty certain that assumption holds.
The GLM library is using a similar trick, except they don't have an array member at all, instead providing an indexing operator that returns (&this->x)[idx].
This is by no ways guaranteed to work as it uses implementation-defined and possibly undefined behaviour. A sensible implementation will probably behave as expected though.
template<int constSize>
class VecFloatFix{
public:
union {
float database[constSize];
struct {
int x, y, z;
};
};
};
This also leaves database public. Don't see a way around this, but no big deal since you provide operator[] anyway.
This assumes constSize >= 3. If you need smaller sizes, this is doable through a bit more hackery. All vectors will have x y and z members but only 3D and above will have them all usable. The 2D vector will have only x and y usable (any use of z is likely to result in an error) and the 1D vector will have just x. Note I refuse to take responsibility for any of the following.
template<int constSize>
class VecFloatFix{
public:
union {
float database[constSize];
struct {
float x;
};
struct {
spacer<constSize, 1> sp1;
typename spacer<constSize, 1>::type y;
};
struct {
spacer<constSize, 2> sp2;
typename spacer<constSize, 2>::type z;
};
};
};
where spacer is defined this way:
template <int N, int M, bool enable>
struct filler;
template <int N, int M>
struct filler<N, M, true>
{
float _f[M];
typedef float type;
};
template <int N, int M>
struct filler<N, M, false>
{
struct nothing {};
typedef nothing type;
};
template <int N, int M>
struct spacer
{
filler<N, M, (N>M)> _f;
typedef typename filler<N, M, (N>M)>::type type;
};
Test drive:
VecFloatFix<4> vec4;
VecFloatFix<3> vec3;
VecFloatFix<2> vec2;
VecFloatFix<1> vec1;
`smoke test`
vec3.database[0] = 42;
vec2.database[1] = 99;
std::cout << vec3.x << std::endl;
std::cout << vec2.y << std::endl;
// make sure `y` aliases `database[1]`
std::cout << & vec2.y << std::endl;
std::cout << & vec2.database[1] << std::endl;
// make sure sizes are as expected
std::cout << sizeof(vec4) << " " << sizeof (vec3) << " " << sizeof(vec2) << " " << sizeof(vec1) << std::endl;
Is there an idiom for a strict typedef in C++, possibly using templates?
Something like:
template <class base_type, int N> struct new_type{
base_type p;
explicit new_type(base_type i = base_type()) : p(i) {}
};
typedef new_type<int, __LINE__> x_coordinate;
typedef new_type<int, __LINE__> y_coordinate;
So I can make something like this a compile time error:
x_coordinate x(5);
y_coordinate y(6);
x = y; // whoops
The __LINE__ in there looks like it might be trouble, but I'd prefer not to have to manually create a set of constants merely to keep each type unique.
I'm using something similar in my project. Only I use type tagging instead of int. Works well in my particular application.
template <class base_type, class tag> class new_type{
public:
explicit new_type(base_type i = base_type()) : p(i) {}
//
// All sorts of constructors and overloaded operators
// to make it behave like built-in type
//
private:
base_type p;
};
typedef new_type<int, class TAG_x_coordinate> x_coordinate;
typedef new_type<int, class TAG_y_coordinate> y_coordinate;
Note that TAG_* classes don't need to be defined anywhere, they are just tags
x_coordinate x (1);
y_coordinate y (2);
x = y; // error
No. There are proposals for it to go into the next standard (C++14, or perhaps C++17), but not in C++11.
With C++11:
#include <stdio.h>
struct dummy {};
struct NotMineType
{
NotMineType(dummy) {}
};
template <int N>
struct type_scope
{
struct MyOwnType
{
};
struct ConvertedToMineType : NotMineType
{
template <typename ...Args>
ConvertedToMineType(Args... args) : NotMineType(args...) {};
};
enum myint : int {};
};
typedef type_scope<0>::MyOwnType x1;
typedef type_scope<1>::MyOwnType x2;
typedef type_scope<0>::ConvertedToMineType y1;
typedef type_scope<1>::ConvertedToMineType y2;
typedef type_scope<0>::myint i1;
typedef type_scope<1>::myint i2;
void foo(x1) { printf("x1\n"); }
void foo(x2) { printf("x2\n"); }
void foo(y1) { printf("y1\n"); }
void foo(y2) { printf("y2\n"); }
void foo(i1) { printf("i1\n"); }
void foo(i2) { printf("i2\n"); }
int main()
{
foo(x1());
foo(x2());
foo(y1(dummy()));
foo(y2(dummy()));
foo(i1());
foo(i2());
}
Output:
x1
x2
y1
y2
i1
i2
Compilers:
Visual Studio 2015, GCC 4.8.x