Search code examples
c++stdmapmost-vexing-parse

Variables does not have class type, even though it is defined


I am trying to write a class which defines a std::map. The comparator of the map must be a function pointer. The function pointer can be passed to the class as an argument in class's constructor.

Below is the code I wrote:

#include <iostream>
#include <map>
#include <string>
#include <functional>

typedef std::function<bool(std::string x, std::string y)> StrComparatorFn;

bool FnComparator(std::string x, std::string y) {
  return strtoul(x.c_str(), NULL, 0) < strtoul(y.c_str(), NULL, 0);
}

class MyClass {
 public:
  MyClass(StrComparatorFn fptr):fn_ptr(fptr){};

  void Insert() {
    my_map.insert(std::pair<std::string, std::string>("1", "one"));
    my_map.insert(std::pair<std::string, std::string>("2", "two"));
    my_map.insert(std::pair<std::string, std::string>("10", "ten"));
  }

  void Display() {
    for (auto& it : my_map) {
      std::cout << it.first.c_str() << "\t => " << it.second.c_str() << "\n";
    }
  } 
 private:
  StrComparatorFn fn_ptr;
  std::map<std::string, std::string, StrComparatorFn> my_map(StrComparatorFn(fn_ptr));
};

int main() {
  MyClass c1(&FnComparator);
  c1.Insert();
  c1.Display();
}

I am getting a compile error in Insert:

error: '((MyClass*)this)->MyClass::my_map' does not have class type
 my_map.insert(std::pair<std::string, std::string>("1", "one"));

Any solution to this issue?


Solution

  • That line

    std::map<std::string, std::string, StrComparatorFn> my_map(StrComparatorFn(fn_ptr));
    

    has a problem known as the most vexing parse. Basically, everything that can be interpreted as a function, will be:

    Foo f(); //f is a function! Not a variable
    

    In your case, my_map is parsed as a declared function without a definition. Using curly braces instead of curved braces will solve the problem, as list initialization can never be interpreted as a function:

    std::map<std::string, std::string, StrComparatorFn> my_map{ StrComparatorFn(fn_ptr) };