How to get rid of an enumeral mismatch error in C++? - c++

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?

Related

Converting between instances of a class template using a member function

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);
};

Template (de)activated member variables

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;
}

Using Parameter Pack Expansion to Generate a Constexpr

I have the following code:
#include <vector>
#include <array>
using std::vector;
enum EventType {
EventType_Collision,
EventType_Accelerate,
EventType_Glide
};
template<class T, EventType... events>
class A {
private:
static unsigned short CalcBitMask(EventType e) { return 1 << e; }
static constexpr unsigned short listeners = 0 | CalcBitMask(events)...;
protected:
//static constexpr int InternalGetType() { return 0; }
public:
static constexpr int GetType() { return T::InternalGetType(); }
static constexpr int GetListeners() { return listeners; }
};
class B : public A<B, EventType_Accelerate, EventType_Collision > {
friend class A<B, EventType_Accelerate, EventType_Collision>;
protected:
static constexpr int InternalGetType() { return 1; }
};
I am trying to create a bitmask based on the EvenType arguments passed into the template. Unfortunately the number of EvenTypes passed is variadic. But since we have all the arguments at compile time it seems like it should be more than possible to calculate a value based on the given arguments at compile time as a constexpr. What I get on the other hand is:
expression did not evaluate to a constant
For the listeners variable. Any ideas? Thanks in advance.
P.S. On a completely unrelated note if anyone has any idea how I can eliminate the lengthy friend class declaration without taking a performance hit and keeping the InternalGetType() function hidden I would love and greatly appreciate hearing it.
Edit
In response to a recent suggestion I am limited to using C++14
Edit
This is what I have done to make it work using recursive template calls
crtp.h
#pragma once
#include <vector>
#include <array>
using std::vector;
enum EventType {
EventType_Collision,
EventType_Accelerate,
EventType_Glide
};
template<class T, EventType... events>
class A {
private:
template <EventType Last>
static constexpr unsigned short BitCalc() {
return 1 << Last;
}
template <EventType First, EventType Second, EventType ...Rest>
static constexpr unsigned short BitCalc() {
return BitCalc<First>() | BitCalc<Second, Rest...>();
}
static constexpr unsigned short listeners = BitCalc<events...>();
protected:
//static constexpr int InternalGetType() { return 0; }
public:
static constexpr int GetType() { return T::InternalGetType(); }
static constexpr int GetListeners() { return listeners; }
};
class B : public A<B, EventType_Accelerate, EventType_Collision > {
friend class A<B, EventType_Accelerate, EventType_Collision>;
protected:
static constexpr int InternalGetType() { return 1; }
};
main.cpp
#include "ctrp.h"
#include <iostream>
#include <vector>
#include<bitset>
using std::cout;
using std::vector;
using std::getchar;
using std::endl;
int main() {
B b;
cout << "Bitmask: " << std::bitset<16>(b.GetListeners());
getchar();
return 0;
}
If you can use C++17, fold expressions (see HolyBlackCat's answer) is (IMHO) a way really simple and elegant to solve the problem.
If you can't use C++17... the best I can imagine is the development of a static constexpr method for class A; something as follows
constexpr static unsigned short calcCombinedBitMask ()
{
using unused = unsigned short [];
unsigned short ret { 0 };
(void)unused { 0, ret |= CalcBitMask(events)... };
return ret;
}
So you can initialize listener in this way
static constexpr unsigned short listeners = calcCombinedBitMask();
For C++11, I suggest a solution a little different from you own
static constexpr unsigned short CalcBitMask (EventType e)
{ return 1 << e; }
static constexpr unsigned short BitCalc()
{ return 0; }
template <EventType First, EventType ... Rest>
static constexpr unsigned short BitCalc()
{ return CalcBitMask(First) | BitCalc<Rest...>(); }
That asks for fold expressions. Note that they're a relatively new feature, added in C++17.
static constexpr unsigned short listeners = (CalcBitMask(events) | ...);
Also you forgot to make CalcBitMask() constexpr.

Should a friend operator in a class with enum parameters be found by Koenig lookup?

Consider the following code:
enum A : unsigned { a = 1, b = 2, c = 4 };
class B
{
friend constexpr A operator|(A a1, A a2)
{ return A(unsigned(a1) | unsigned(a2)); }
};
template <A a>
class C
{
};
int main()
{
C<a|c> c;
}
When compiled with g++ (4.8.1, -std=c++1), I get the following error:
test.C: In function ‘int main()’:
test.C:16:12: error: invalid conversion from ‘unsigned int’ to ‘A’ [-fpermissive]
C<a|c> c;
Which tells me that the operator is not being found. However, if the code is changed to:
enum A : unsigned { a = 1, b = 2, c = 4 };
constexpr A operator|(A a1, A a2)
{ return A(unsigned(a1) | unsigned(a2)); }
template <A a>
class C
{
};
int main()
{
C<a|c> c;
}
Then it compiles and runs fine. Is the error in the first case a compiler error, or I do misunderstand something? I would like to use the method of Boost.Operators to easily define operators by declaring a class with base classes from templates which define the operators, but this result precludes that in this case.
Thanks for any help.
Another way to solve it (other than jogojapan already mentioned), is to simply declare the friend function outside the scope.
enum A : unsigned { a = 1, b = 2, c = 4 };
//declaration
constexpr A operator|(A a1, A a2);
class B
{
//definition inside, ok.
friend constexpr A operator|(A a1, A a2)
{ return A(unsigned(a1) | unsigned(a2)); }
};
template <A a>
class C
{
};
int main()
{
C<a|c> c;
}
Okay, I took another approach, and here's code which solves my problem:
template <typename UNSIGNED>
struct BitwiseEnum
{
enum class Enum : UNSIGNED
{
};
constexpr static Enum value(unsigned bit)
{
return Enum(UNSIGNED(1) << bit);
}
friend constexpr Enum operator|(Enum a, Enum b)
{
return Enum(UNSIGNED(a)|UNSIGNED(b));
}
friend constexpr Enum operator&(Enum a, Enum b)
{
return Enum(UNSIGNED(a)&UNSIGNED(b));
}
friend constexpr Enum operator~(Enum a)
{
return Enum(~UNSIGNED(a));
}
};
class MyMask : public BitwiseEnum<unsigned long>
{
};
typedef MyMask::Enum Mask;
constexpr static Mask a = MyMask::value(0);
constexpr static Mask b = MyMask::value(1);
constexpr static Mask c = MyMask::value(2);
constexpr static Mask d = MyMask::value(3);
template <Mask A>
class B
{
};
int main()
{
B<a|b> test;
}
Now, when I defined a lot of enums like "MyMask", it can be done fairly simply, without much more code than a simply defined enum would have. And it behaves as one would "expect" from a bit field enum, can be used in strongly type checked template arguments, etc.

Is it possible to calculate number factorial at compile time, but without enums

I want to calculate factorial at the compile-time. I found some way to solve the problem, but I want to know if there any another solution for this problem without using enum s. Here the solution using enum s.
#include <iostream>
template <int n>
struct fact
{
enum{value = n*fact<n-1>::value};
};
template<>
struct fact<1>
{
enum{value = 1};
};
int main()
{
std::cout << fact<10>::value;
}
If there is no another solution, please describe why the enum s are must.
While there are alternative notations, It's written that way because more compilers accept that enum-style notation. The language supports const integral-type class members with an inline initialization, but some compilers aren't compliant with the standard in that regard. On compilers that are compliant in this regard, the following works just fine:
#include <iostream>
template <unsigned int n>
struct fact
{
static const unsigned int value = n*fact<n-1>::value;
};
template<>
struct fact<0>
{
static const unsigned int value = 1;
};
int main()
{
std::cout << fact<10>::value << "\n";
}
Replace,
enum{value};
with,
static int const value; // or unsigned int
enums are must because they suppose to be resolved at compile time. Which assures that whatever result you calculated must have been done at compile time. Other such type is static int const (means any integral type).
To illustrate:
enum E {
X = strlen(s); // is an error, because X is a compile time constant
};
Alternatively, you can use static const members:
template <unsigned int n>
struct fact { static const unsigned int value = n * fact<n-1>::value; }