Search code examples
c++operator-overloadingstdmapstd-pairallocator

C++(3364) : operator -> or ->* applied instead of pointer type


I have declared and populated a map : std::map<std::string, std::vector<std::pair<std::string, std::vector<std::vector<float>>>>> data;.

I have a print function to print the contents of the map which is as follows :

void print() {
    for (auto it : data) {
        std::cout << it->first << "\n";
        for (auto iter : it->second) {
            std::cout << iter->first << "\n";
            for (auto val : iter->second) {
                std::cout << val->second << "";
            }
            std::cout << "\n";
        }
        std::cout << "\n";
    }
}

But, when I compile the program, I get the following error :

operator -> or ->* applied to "std::pair<const std::string,
std::vector<std::pair<std::string,
std::vector<std::vector<float, 
std::allocator<float>>, 
std::allocator<std::vector<float, std::allocator<float>>>>>, 
std::allocator<std::pair<std::string, 
std::vector<std::vector<float, std::allocator<float>>, 
std::allocator<std::vector<float, std::allocator<float>>>>>>>>" 
instead of to a pointer typeC/C++(3364)

I don't know what I'm doing wrong.

I also tried accessing the map data through (*it).first, which throws the following error :

no operator "*" matches these operandsC/C++(349)
myfile.cpp(80, 23): operand types are: * std::pair<const std::string, 
std::vector<std::pair<std::string, std::vector<std::vector<float, 
std::allocator<float>>, std::allocator<std::vector<float, 
std::allocator<float>>>>>, std::allocator<std::pair<std::string, 
std::vector<std::vector<float, std::allocator<float>>, 
std::allocator<std::vector<float, std::allocator<float>>>>>>>>

What should I do instead of what I have did? Please let me know if I'm wrong anywhere in the code.


Solution

  • While trying to unroll your map, you made several mistakes. You need to go from outer to inner structures.

    And you need to understand that using a range based for loop already unrolls one level.

    In order to learn it, you should avoid to use the auto key word, because then you must name the correct data type.

    All the above will lead to:

    #include <iostream>
    #include <vector>
    #include <map>
    #include <utility>
    using namespace std::string_literals;
    
    std::map<std::string, std::vector<std::pair<std::string, std::vector<std::vector<float>>>>> data{
        {"OuterMapS1"s, {  {"v1PairLeft1"s, {{1.1f,2.2f},{3.3f,4.4f}}},{"v2PairLeft2"s, {{5.5f,6.6f,7.7f},{1.2f,1.3f}}}}},
        {"OuterMapS2"s, {  {"v3PairLeft3"s, {{7.0f,8.0f,9.0f},{3.5f,4.6f}}},{"v4PairLeft4"s, {{3.5f,3.6f,3.7f},{4.2f,4.3f,4.4f}}}}}
    };
    
    int main() {
        for (const std::pair<const std::string,std::vector<std::pair<std::string,std::vector<std::vector<float>>>>>& p1 : data) {
            std::cout << p1.first << '\n';
            for (const std::pair<std::string, std::vector<std::vector<float>>>& p2 : p1.second) {
                std::cout << '\t' << p2.first << '\n';
                for (const std::vector<float> &vOuter : p2.second) { 
                    std::cout << "\t\t\t";
                    for (const float& f : vOuter) {
                        std::cout << f << '\t';
                    }
                    std::cout << '\n';
                }
            }
            std::cout << '\n';
        }
    }
    

    Additionally, to define your own types with the using statement will also be helpful. Then you can first build your data structure from inside out. And, for printing, you can use the predefined types.

    This will make life a little bit simpler:

    #include <iostream>
    #include <vector>
    #include <map>
    #include <utility>
    using namespace std::string_literals;
    
    using FloatVec = std::vector<float>;
    using Float2dVec = std::vector<FloatVec>;
    using PairStr2dFloatVec = std::pair<std::string, Float2dVec>;
    using VecPairStr2dFloatVec = std::vector<PairStr2dFloatVec>;
    using MyMap = std::map<std::string, VecPairStr2dFloatVec>;
    using MyMapPair = MyMap::value_type;
    
    MyMap data{
        {"OuterMapS1"s, {  {"v1PairLeft1"s, {{1.1f,2.2f},{3.3f,4.4f}}},{"v2PairLeft2"s, {{5.5f,6.6f,7.7f},{1.2f,1.3f}}}}},
        {"OuterMapS2"s, {  {"v3PairLeft3"s, {{7.0f,8.0f,9.0f},{3.5f,4.6f}}},{"v4PairLeft4"s, {{3.5f,3.6f,3.7f},{4.2f,4.3f,4.4f}}}}}
    };
    
    int main() {
        for (const MyMapPair& p1 : data) {
            std::cout << p1.first << '\n';
            for (const PairStr2dFloatVec& p2 : p1.second) {
                std::cout << '\t' << p2.first << '\n';
                for (const FloatVec& vOuter : p2.second) {
                    std::cout << "\t\t\t";
                    for (const float& f : vOuter) {
                        std::cout << f << '\t';
                    }
                    std::cout << '\n';
                }
            }
            std::cout << '\n';
        }
    }
    

    And, last but not least, you can use structured bindings for std::map and std::pair, this time with auto again, but again, a bit more readable:

    #include <iostream>
    #include <vector>
    #include <map>
    #include <utility>
    using namespace std::string_literals;
    
    using FloatVec = std::vector<float>;
    using Float2dVec = std::vector<FloatVec>;
    using PairStr2dFloatVec = std::pair<std::string, Float2dVec>;
    using VecPairStr2dFloatVec = std::vector<PairStr2dFloatVec>;
    using MyMap = std::map<std::string, VecPairStr2dFloatVec>;
    using MyMapPair = MyMap::value_type;
    
    MyMap data{
        {"OuterMapS1"s, {  {"v1PairLeft1"s, {{1.1f,2.2f},{3.3f,4.4f}}},{"v2PairLeft2"s, {{5.5f,6.6f,7.7f},{1.2f,1.3f}}}}},
        {"OuterMapS2"s, {  {"v3PairLeft3"s, {{7.0f,8.0f,9.0f},{3.5f,4.6f}}},{"v4PairLeft4"s, {{3.5f,3.6f,3.7f},{4.2f,4.3f,4.4f}}}}}
    };
    
    int main() {
        for (const auto& [outerString, outerVector] : data) {
            std::cout << outerString << '\n';
            for (const auto& [innerString, nextVector] : outerVector) {
                std::cout << '\t' << innerString << '\n';
                for (const FloatVec& fVector : nextVector) {
                    std::cout << "\t\t\t";
                    for (const float& f : fVector) {
                        std::cout << f << '\t';
                    }
                    std::cout << '\n';
                }
            }
            std::cout << '\n';
        }
    }
    

    Unfortunately, the complicated data structure will make it a bit difficult to access sub-elements.