1

I did two classes, The first is template class Bit<size> that convert decimal number to a binary. The second is LogicalExpression class.

Bit class:

template<int size>
class Bit
{
public:
    Bit(int);
    void ConvertToBinary(int);
    bool number[size];
    int bit;
};

template <int size> Bit<size>::Bit(int decimalNumber)
{
    this->bit = 0;
    ConvertToBinary(decimalNumber);
}

template <int size> void Bit<size>::ConvertToBinary(int decimalNumber)
{
    number[size - ++this->bit] = decimalNumber % 2;
    if (size != this->bit) {
        ConvertToBinary(decimalNumber / 2);
    }
}

LogicalExpression class:

#include "Bit.h"
class LogicalExpression
{
private:
    char* expression;
    char* variables;
    int expLenght;
    int varLenght;

public:
    LogicalExpression(char*);
    ~LogicalExpression();
    bool ExpressionToBoolean(char*, Bit<????>); //here is the problem

I want to use the LogicalExpression class as a normal non-template class, as a result I do not know how to declare const argument for Bit<???>, it should be Bit<varLenght>, but varLenght is non-const value and i do not want to do LogicalExpression<varLenght> obj . Hope that my English not so bad, for not understanding me.

Sevi
  • 863
  • 4
  • 15
  • 33

1 Answers1

0

The problem here is possibly a misunderstanding of how templates work.

Templates are evaluated at compile time. Therefore the value inbetween < > can not contain a non-const. Its simply not possible because templates are not evaluated at run time. This is actually a strength, not a weakness (see TMP). For comparison they are more like pre-processor defines then say a function call but they are actually not the same thing as macros

In this case you need to rethink your design. in this part:

 template<int size>
class Bit
{
public:
    Bit(int);
    void ConvertToBinary(int);
    bool number[size];
    int bit;
};

You either want "number" to be a dynamic array so that it would either become something like:

class Bit
{
public:
    Bit(int length){ number = new bool[length]; } ;
    ~Bit(){delete number;}
    void ConvertToBinary(int);
    bool* number;
    int bit;
};

it doesn't need to be a template and would be used like:

bool ExpressionToBoolean(char*)
{
    Bit foo(varLength); 
}

You could use std::vector for simplicity.

OR "LogicalExpression" should be a template class (which you have said you don't want)

 template<int varLenght>
class LogicalExpression
{
private:
    char* expression;
    char* variables;
    int expLenght;

public:
    LogicalExpression(char*);
    ~LogicalExpression();
    bool ExpressionToBoolean(char*, Bit<varLenght>); //here is the problem

But really this boils down to a question of where you want your memory allocated, do you want it on the heap or the stack?

  • Heap : Dynamic array (can be evaluated at run time)
  • stack : Templates (can not be evaluated at run time)

If you don't care, i would probably just stick with the dynamic array approach because you could easily over complicate the problem with templates...but this problem may be suited to TMP based on your requirements. If you want it on stack then you will have to use some form of

LogicalExpression< "const" > obj

"somewhere", which if its a syntactical taste you could use something like:

   typedef LogicalExpresion8Bit LogicalExpression<8>

If you want dynamic evaluation then you have to either use dynamic memory or something a bit crazier like a combination of polymorphic and interfaces which will most likely lead to more memory on the stack then you actually want/need, not to mention a lot more code...(i.e. each variant stored in an array and selected via index).

Community
  • 1
  • 1
chrispepper1989
  • 2,100
  • 2
  • 23
  • 48
  • 1
    Templates are "evaluated" at compile time, and certainly not in the same translation phase as macros. – Columbo Nov 25 '14 at 11:30
  • good point @Columbo an oversimplification on my part and I have updated the answer, not sure if its that clear. I just know a lot of people find it easier to think of them as macros in the beginning – chrispepper1989 Nov 25 '14 at 11:36
  • My idea to use `Bit(int decimalNumber)` and not `Bit(int lenght)` is to allow to check a logical expression such **a&b&c == a|b**. I can't compare 3bit to 2bit. And of course also there a way to use `Bit(int decimalNumber, int bitLenght)`, but I left this for last case. – Sevi Nov 25 '14 at 13:16
  • not sure how templates would help you achieve this. In fact you might find that using templates would have the opposite effect of what you want. surely what you want in this case is normal classes with operator overloads? – chrispepper1989 Nov 25 '14 at 15:19
  • @chrispepper1989 Yes. – Sevi Nov 25 '14 at 22:00