I can't seem to make the map template work for me.

//#include "PrecedenceXY.h"
#include <map>
#include <string>
using namespace std;

map<string, int> normalXPrecedence;
map<string, int> normalYPrecedence;


normalXPrecedence["x"]   =  1;
normalXPrecedence["x^2"]      =  2;
normalXPrecedence["x^3"]         =  3;
normalXPrecedence["x^4"]      =  4;
normalXPrecedence["x^5"]      =  5;
normalXPrecedence["x^6"]     =  6;
ect, filling up both X and Y lists.

wxDev-C++ gives these errors:

10 FilepathCut expected constructor, destructor, or type conversion before '=' token 
10 FilepathCut expected `,' or `;' before '=' token 
11 FilepathCut expected constructor, destructor, or type conversion before '=' token 
11 FilepathCut expected `,' or `;' before '=' token 
12 FilepathCut expected constructor, destructor, or type conversion before '=' token

and so on for every single time I try to add something into the list.

So, could someone tell me what Im doing wrong? I tried to initialize the map in a variety of ways like:
map<string, int> normalXPrecedence = map<string, int>::map();
map<string, int> normalXPrecedence = map();
But nothing works *sigh* Can anyone help me?

Recommended Answers

All 13 Replies

normalXPrecedence["x"]   =  1;
normalXPrecedence["x^2"]      =  2;
normalXPrecedence["x^3"]         =  3;
normalXPrecedence["x^4"]      =  4;
normalXPrecedence["x^5"]      =  5;
normalXPrecedence["x^6"]     =  6;

Are these lines actually in the global scope, or are you summarizing by removing the function that they reside in? Only declarations and definitions are allowed in the global scope, and assignment to an existing object isn't either. This works:

#include <map>

std::map<int, int> m;

int main()
{
  m[10] = 1;
}

This doesn't:

#include <map>

std::map<int, int> m;

m[10] = 1;

int main()
{
}
normalXPrecedence["x"]   =  1;
normalXPrecedence["x^2"]      =  2;
normalXPrecedence["x^3"]         =  3;
normalXPrecedence["x^4"]      =  4;
normalXPrecedence["x^5"]      =  5;
normalXPrecedence["x^6"]     =  6;

Are these lines actually in the global scope, or are you summarizing by removing the function that they reside in? Only declarations and definitions are allowed in the global scope, and assignment to an existing object isn't either. This works:

#include <map>

std::map<int, int> m;

int main()
{
  m[10] = 1;
}

This doesn't:

#include <map>

std::map<int, int> m;

m[10] = 1;

int main()
{
}

I see, that would make sense I guess...*scratch* Now Im going to have to find some way to initialize them I guess. *sigh* Function calls....unecessary function calls....ugly.

Thanks!

Also, I purposely changed the variable, key, and file names so that I wouldn't have to say what the project was. :p

Member Avatar for iamthwee

>Also, I purposely changed the variable, key, and file names so that I wouldn't have to say what the project was.

Oh I want to know what the project is...:sad:

Please tell us??

I see, that would make sense I guess...*scratch* Now Im going to have to find some way to initialize them I guess. *sigh* Function calls....unecessary function calls....ugly.

I assume that this is some kind of a lookup table? How about wrapping your map inside a class, and using the constructor to initialise it?

>Now Im going to have to find some way to initialize them I guess.
You can initialize an array of pairs, and then use one of the std::map constructors with the array to initialize normalXPrecedence:

#include <iostream>
#include <string>
#include <map>
#include <utility>

template <typename T, int N>
char (&array(T(&)[N]))[N];

std::pair<std::string, int> init[] = {
  std::pair<std::string, int> ( "x", 1 ),
  std::pair<std::string, int> ( "x^2", 2 ),
  std::pair<std::string, int> ( "x^3", 3 ),
  std::pair<std::string, int> ( "x^4", 4 ),
  std::pair<std::string, int> ( "x^5", 5 ),
  std::pair<std::string, int> ( "x^6", 6 )
};

std::map<std::string, int> normalXPrecedence ( init, init + sizeof array ( init ) );

int main()
{
  std::map<std::string, int>::iterator it = normalXPrecedence.begin();

  while ( it != normalXPrecedence.end() ) {
    std::cout<< it->first <<" -- "<< it->second <<'\n';
    ++it;
  }
}

That saves you the effort of using a function or hardcoded loop to populate the map.

>Now Im going to have to find some way to initialize them I guess.
You can initialize an array of pairs, and then use one of the std::map constructors with the array to initialize normalXPrecedence:

#include <iostream>
#include <string>
#include <map>
#include <utility>

template <typename T, int N>
char (&array(T(&)[N]))[N];

std::pair<std::string, int> init[] = {
  std::pair<std::string, int> ( "x", 1 ),
  std::pair<std::string, int> ( "x^2", 2 ),
  std::pair<std::string, int> ( "x^3", 3 ),
  std::pair<std::string, int> ( "x^4", 4 ),
  std::pair<std::string, int> ( "x^5", 5 ),
  std::pair<std::string, int> ( "x^6", 6 )
};

std::map<std::string, int> normalXPrecedence ( init, init + sizeof array ( init ) );

int main()
{
  std::map<std::string, int>::iterator it = normalXPrecedence.begin();

  while ( it != normalXPrecedence.end() ) {
    std::cout<< it->first <<" -- "<< it->second <<'\n';
    ++it;
  }
}

That saves you the effort of using a function or hardcoded loop to populate the map.

Ooer! Awesome! Thanks!

Ok ok, I'll tell you what it's for. It's a table to store strings, and the number represents the precedence of that string in relation to the others in that list. I can then use parts of that list in another list and sort them based on the int they're mapped to. I know I could have used an enumeration or all kinds of other things, but I wanted to use a map because a map allows me to change the ints at run time and I want to leave that option open instead of using Macroed definitions or something.

Bleh, and here I thought I got everything,

Could you explain what this is?

init + sizeof array ( init )

from

std::map<std::string, int> normalXPrecedence ( init, init + sizeof array ( init ) );

I think it has something to do with

template <typename T, int N>
char (&array(T(&)[N]))[N];

but Im not quite sure, since I don't see the <> to intialize that template or anything.

Actually nevermind, Im just going to move it into a class, requires less rewriting. *grumble* Kind of annoying though, I didn't really want another class just for this.

Member Avatar for iamthwee

Can I just ask does this have anything to do with sorting polynomials into their order of precedence or is the:
x
x^2
x^3

just a decoy, masking sumthing else?

>Could you explain what this is?
That's a template trick. If you don't want it, you can just replace the "init + sizeof array ( init )" part with the constant 6 and be done with it. The template trick is a C++ variant of the popular C macro to find the number of elements in an array:

#define length(x) (sizeof (x) / sizeof *(x))

The trick part is that the template function (which needs no body since sizeof doesn't actually call the function) accepts an array of type T with N elements, but returns an array also with N elements, but of type char. So if you pass an array of N ints to the function and take the size of the result, you'll take the size of an array of N chars, which is guaranteed to be equal to N. And that gives you the value of N without using macros or magic numbers.

>Im just going to move it into a class, requires less rewriting.
You have a strange idea of "less rewriting". :confused:

>Could you explain what this is?
That's a template trick. If you don't want it, you can just replace the "init + sizeof array ( init )" part with the constant 6 and be done with it. The template trick is a C++ variant of the popular C macro to find the number of elements in an array:

#define length(x) (sizeof (x) / sizeof *(x))

The trick part is that the template function (which needs no body since sizeof doesn't actually call the function) accepts an array of type T with N elements, but returns an array also with N elements, but of type char. So if you pass an array of N ints to the function and take the size of the result, you'll take the size of an array of N chars, which is guaranteed to be equal to N. And that gives you the value of N without using macros or magic numbers.

>Im just going to move it into a class, requires less rewriting.
You have a strange idea of "less rewriting". :confused:

Well, it requires less rewriting because I just moved it all in the constructor and left it at that. Also, is that array of char's useful since they are null terminated? And could you explain exactly HOW the template is doing that? I don't see new chars or anything, :(

Also, in regards to the previous post, yes the "x" and "x^2" is a mask hiding stuff.

EDIT: Ok so Im an idiot and didn't see the char( part, but the inside of that still confuses me. :p

>And could you explain exactly HOW the template is doing that?
Sure. First, as I'm sure you know, the sizeof operator doesn't evaluate its operand. sizeof simply calculates the size of the type of the end result of the operand. If the operand is an expression, sizeof gives you the size of the type of the result of the expression. If the operand is a function call, sizeof gives you the size of the type of the return value.

So I built on the fact that you can return a reference to an array, and sizeof will give you the size of the array in bytes:

#include <iostream>

char (&foo())[5];

int main()
{
  std::cout<< sizeof foo() <<'\n';
}

If you pass the size of the array as a template argument, you don't need to specify it as a constant as I did in the example above, so you can find the size of an array of char of any size by making the function a template:

#include <iostream>

template <int N>
char (&foo())[N];

int main()
{
  std::cout<< sizeof foo<5>() <<'\n';
}

Of course, that's damn near useless because you still have to specify the size, and that defeats the purpose of the solution I wanted. So the size needs to be implicitly deduced through an argument to the function, and that means passing a reference to an array of the size we want:

#include <iostream>

template <int N>
char (&foo(char (&arg)[N]))[N];

int main()
{
  char a[5];
  std::cout<< sizeof foo(a) <<'\n';
}

Now, this still isn't very useful because the size in bytes of an array of char is the same as the number of elements because the size of a char is guaranteed to be 1. The trick here is to notice that the type of the argument is irrelevant; only the size matters, so you can change the type of the argument to the type of the array you plan to pass:

#include <iostream>

template <int N>
char (&foo(int (&arg)[N]))[N];

int main()
{
  int a[5];
  std::cout<< sizeof foo(a) <<'\n';
}

That still gives the correct size of 5, even for an array of integers, the size of which are guaranteed *not* to be 1. Now, if you deduce the type of the array argument through the template, you have a nice generic array size component:

#include <iostream>

template <typename T, int N>
char (&foo(T (&arg)[N]))[N];

int main()
{
  int a[5];
  std::cout<< sizeof foo(a) <<'\n';
}

Finally, to finish off the solution, the argument name isn't needed because this is only a function declaration and the name isn't used. Also, the name of the function template should reflect what we want to do with it. I chose to call the function "array" because "sizeof array(a)" makes all kinds of sense to me. It smoothly reads "take the size of the array a". So the final template is:

#include <iostream>

template <typename T, int N>
char (&array(T(&)[N]))[N];

int main()
{
  int a[5];
  std::cout<< sizeof array(a) <<'\n';
}

Thanks again!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.