wait_wut
wait_wut

Reputation: 57

Adding a struct into a map

I'm having trouble adding a struct into a map. I don't really understand the error.

There are 2 errors:

  1. I can't declare a map with 'struct' type
  2. I can't use insert to 'insert' my struct into the map

What am I doing wrong?

#include <iostream>
#include <map>

int main()
{

    typedef struct 
    {   
        std::string stringVar;
        unsigned unsignedVar;
        float floatVar;
    } MyTypeDefStruct;

    MyTypeDefStruct myTypeDefStruct;
    myTypeDefStruct.stringVar = "myStr";
    myTypeDefStruct.unsignedVar = 1000;
    myTypeDefStruct.floatVar = -10.0;

    float anotherFloat = -20.0;

    std::map<MyTypeDefStruct, float> myMap;

    myMap.insert(std::pair<MyTypeDefStruct, float> (myTypeDefStruct, anotherFloat));                                                                                                                                                                                                      

    return 0;
}

error:

test.cpp: In function 'int main()':
test.cpp:21:36: error: template argument for 'template<class _Tp> struct std::less' uses local type 'main()::MyTypeDefStruct'
 std::map<MyTypeDefStruct, float> myMap;
                                ^
test.cpp:21:36: error:   trying to instantiate 'template<class _Tp> struct std::less'
test.cpp:21:36: error: template argument 3 is invalid
test.cpp:21:36: error: template argument for 'template<class _T1, class _T2> struct std::pair' uses local type 'const main()::MyTypeDefStruct'
test.cpp:21:36: error:   trying to instantiate 'template<class _T1, class _T2> struct std::pair'
test.cpp:21:36: error: template argument 4 is invalid
test.cpp:21:43: error: invalid type in declaration before ';' token
 std::map<MyTypeDefStruct, float> myMap;
                                       ^
test.cpp:23:11: error: request for member 'insert' in 'myMap', which is of non-class type 'int'
 myMap.insert(std::pair<MyTypeDefStruct, float> (myTypeDefStruct, anotherFloat));
       ^
test.cpp:23:50: error: template argument for 'template<class _T1, class _T2> struct std::pair' uses local type 'main()::MyTypeDefStruct'
 myMap.insert(std::pair<MyTypeDefStruct, float> (myTypeDefStruct, anotherFloat));
                                              ^
test.cpp:23:50: error:   trying to instantiate 'template<class _T1, class _T2> struct std::pair'

Upvotes: 2

Views: 2725

Answers (4)

Kerek
Kerek

Reputation: 1110

There are several issues in your code:

  1. The struct should defined outside of the function main, can't see a reason why you want to define it there in this case, and since it is local inside of main, you can't use it anywhere else!
  2. You are using the C-style typedef struct ... StructName instead of simply using struct MyStruct.
  3. Your struct doesn't implement the operator<, hence, since std::map is an ordered map, and it doesn't have anyway to compare two keys (here, the key is your struct), it doesn't able to insert any pair.
  4. Your struct doesn't implement the operator== which is important to actually retrieving the value of a certain key... You should be able to check if the keys are similar.
  5. Another small fix - using std::make_pair instead of its ctor.

Your code should look like:

#include <iostream>
#include <map>

struct MyStruct
{   
    std::string stringVar;
    unsigned unsignedVar;
    float floatVar;

    friend bool operator<(const MyStruct& l, const MyStruct& r)
    {
        return std::tie(l.stringVar, l.unsignedVar, l.floatVar)
             < std::tie(r.stringVar, r.unsignedVar, r.floatVar);
    }

    friend bool operator==(const MyStruct& l, const MyStruct& r)
    {
        return std::tie(l.stringVar, l.unsignedVar, l.floatVar)
             == std::tie(r.stringVar, r.unsignedVar, r.floatVar);
    }
};  

int main()
{
    MyStruct my_struct;
    my_struct.stringVar = "myStr";
    my_struct.unsignedVar = 1000;
    my_struct.floatVar = -10.0;

    float anotherFloat = -20.0;

    std::map<MyStruct, float> myMap;

    myMap.insert(std::make_pair(my_struct, anotherFloat));

    return 0;
}

How did I get to identifying the first problem? In the first error (always look at the first error, the others may be misleading!), it is written:

test.cpp:21:36: error: template argument for 'template<class _Tp> struct std::less' uses local type 'main()::MyTypeDefStruct'
 std::map<MyTypeDefStruct, float> myMap;

Notice that the template initialization here is using main()::MyTypeDefStruct and not MyTypeDefStruct!!! These types are different, and the first is available only in the scope of main()!

The third point is because when you fix the first point, you will get:

error: no match for 'operator<' (operand types are 'const MyStruct' and 'const MyStruct')

Upvotes: 4

Thomas Sablik
Thomas Sablik

Reputation: 16453

A sorted map needs a less operator (operator<) to sort the elements. You have to provide such operator or you have to set a sort function. One possible solution is to implement this operator:

#include <iostream>
#include <map>


struct MyTypeDefStruct {   
    std::string stringVar;
    unsigned unsignedVar;
    float floatVar;
};

bool operator<(const MyTypeDefStruct &lhs, const MyTypeDefStruct &rhs) {
    if (lhs.stringVar < rhs.stringVar) return true;
    if (lhs.stringVar > rhs.stringVar) return false;
    if (lhs.unsignedVar < rhs.unsignedVar) return true;
    if (lhs.unsignedVar > rhs.unsignedVar) return false;
    if (lhs.floatVar < rhs.floatVar) return true;
    return false;
}

int main() {

    MyTypeDefStruct myTypeDefStruct;
    myTypeDefStruct.stringVar = "myStr";
    myTypeDefStruct.unsignedVar = 1000;
    myTypeDefStruct.floatVar = -10.0;

    float anotherFloat = -20.0;

    std::map<MyTypeDefStruct, float> myMap;

    myMap.insert(std::pair<MyTypeDefStruct, float> (myTypeDefStruct, anotherFloat));                                                                                                                                                                                                      

    return 0;
}

Upvotes: 1

asmmo
asmmo

Reputation: 7100

std::map<T>::insert uses a comparator to insert your elements but there is no one defined for your struct, hence try to use something like the following

#include <iostream>
#include <map>
struct MyTypeDefStruct
{
    std::string stringVar;
    unsigned unsignedVar;
    float floatVar;
} ;

bool operator<(const MyTypeDefStruct& lhs, const MyTypeDefStruct& rhs){
    return lhs.unsignedVar < rhs.unsignedVar;
}

int main()
{


    MyTypeDefStruct myTypeDefStruct;
    myTypeDefStruct.stringVar = "myStr";
    myTypeDefStruct.unsignedVar = 1000;
    myTypeDefStruct.floatVar = -10.0;

    float anotherFloat = -20.0;

    std::map<MyTypeDefStruct, float> myMap;

    myMap.insert(std::pair<MyTypeDefStruct, float> (myTypeDefStruct, anotherFloat));

    return 0;
}

Upvotes: 1

ralphmerridew
ralphmerridew

Reputation: 324

The first problem is that map requires a way to compare two myTypeDefStructs. You'll need to do is define operator< or std::less for your class, or pass a comparison functor to the map.

Upvotes: 1

Related Questions