0

I've overloaded my function contains three times

// returns true if char c is contained in unordered map um
bool contains(std::unordered_map<char, op>& um, char c){
    return um.find(c) != um.end();
}

// returns true if string s is contained in unordered map um
bool contains(std::unordered_map<char, op>& um, std::string& s){
    return s.length() == 1 && contains(um, s[0]); 
}

// returns true if string s is contained in unordered map um
bool contains(std::unordered_map<std::string, func>& um, std::string& s){
    return um.find(s) != um.end(); 
}

The parameters are different in each overloaded function. Yet, from the line (contains(opmap, q_front)) I get the error: more than one instance of overloaded function "contains" matches the argument list.

For reference, opmap is of type std::unordered_map<char, op>, and q_front is a string. op in this case is just struct I created- I can post if needed, but I feel it is unnceessary in this case.

My question is why I'm getting this error, as the function call above should uniquely call the second method header: bool contains(std::unordered_map<char, op>& um, std::string& s){ because of the type of opmap matches the first parameter, and the type of q_front is string.

UPDATE:

Full error message:

more than one instance of overloaded function "contains" matches the argument list: -- function "contains(std::unordered_map<char, op, std::hash<char>, std::equal_to<char>, std::allocator<std::pair<const char, op>>> &um, std::string s)" (declared at line 48 of "/Users/raleighclemens/Documents/Calc_cpp/calc.h") -- function "contains(std::unordered_map<char, op, std::hash<char>, std::equal_to<char>, std::allocator<std::pair<const char, op>>> &um, std::string &s)" (declared at line 49) -- argument types are: (std::unordered_map<char, op, std::hash<char>, std::equal_to<char>, std::allocator<std::pair<const char, op>>>, std::string)C/C++(308)

MRE:

#include <iostream>
#include <string>
#include <functional>
#include <unordered_map>

#define LEFT 0
#define RIGHT 1
#define UNARY 0
#define BINARY 1

struct op{
    char symbol;
    uint8_t precedence;
    uint8_t assoc;
    uint8_t type;

    std::function<double (double, double)> ashley;

};

struct func{
    std::string symbol;
    uint8_t type;

    std::function<double (double, double)> ashley;
};

bool contains(std::unordered_map<char, op>& um, char c){
    return um.find(c) != um.end();
}

// returns true if string s is contained in unordered map um
bool contains(std::unordered_map<char, op>& um, std::string& s){
    return s.length() == 1 && contains(um, s[0]); 
}

// returns true if string s is contained in unordered map um
bool contains(std::unordered_map<std::string, func>& um, std::string& s){
    return um.find(s) != um.end(); 
}


int main(int argc, char** argv){

    std::unordered_map<char, op> opmap;
    op op1{'+', 2, LEFT, BINARY, [=] (double a, double b){return a + b;}};
    opmap.emplace('+', op1);

    std::cout << contains(opmap, "+");
    
rjc810
  • 425
  • 1
  • 3
  • 17
  • 4
    Can you provide a [mcve] and the exact error message? – HolyBlackCat Jul 20 '21 at 20:45
  • 3
    Your code contains multiple problems that are probably unrelated, like the use of non-const references for no good reason. Also, you failed to include the entire error message text; that is a bad idea. You might not understand the error, but the error will describe your problem. Include it in a quoted code block. Third, a [mcve] would be very useful, and make solving your problem easy. – Yakk - Adam Nevraumont Jul 20 '21 at 20:47
  • [not reproducible](https://godbolt.org/z/s7WY9s3va) – n. m. could be an AI Jul 20 '21 at 20:53
  • @KenWhite I've updated the original post with the full error message and an MRE – rjc810 Jul 20 '21 at 21:01
  • @Yakk-AdamNevraumont should I be labeling the unordered maps in the parameters as const? – rjc810 Jul 20 '21 at 21:04
  • @HolyBlackCat I've updated the original post with the full error message and an MRE – rjc810 Jul 20 '21 at 21:05
  • Still not reproducible. You're missing necessary includes like `` and ``, and definitions for whatever `LEFT` and `RIGHT` are. So now the code fails to compile for a completely different reason than the one you're describing. – Nathan Pierson Jul 20 '21 at 21:06
  • 2
    Anyway, it turns out to be pretty important to use `const std::string& s` instead of `std::string& s`, because the former allows you to pass temporaries as arguments. In your case you have a temporary that isn't even a `std::string`, it's a `const char[2]`. – Nathan Pierson Jul 20 '21 at 21:08
  • @NathanPierson sorry, what do you mean by "temporaries"? isn't a char array the same as a string? – rjc810 Jul 20 '21 at 21:11
  • 1
    A char array is conceptually a string, but there are many technical differences between one and the actual class `std::string`. As for the `const` thing being important, [here's](https://stackoverflow.com/questions/27463785/cant-pass-temporary-object-as-reference) a good question on the matter. – Nathan Pierson Jul 20 '21 at 21:14
  • 1
    The error message clearly shows the ambiguous overloads are `contains(std::unordered_map &um, std::string s)` and `contains(std::unordered_map &um, std::string &s)`, but there is no overload with a non-reference `std::string s` parameter in the code shown. – Remy Lebeau Jul 20 '21 at 21:29

1 Answers1

3

Which overload you expect to match your call to the below line?

std::cout << contains(opmap, "+");

Overload 1 cannot match, because of your second argument, i.e. "+". Its type is const char[2] and cannot be matched to char.

Overload 2 and 3 cannot match, because the type of "+" has a const qualifier, but in those two overloads your string is passed as a non-const reference.

So, to fix your issue, you should either:

  • change "+" to '+' to use the first overload.
  • change std::string & to const std::string & to use overload 2.
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
TonySalimi
  • 8,257
  • 4
  • 33
  • 62
  • thanks! but why is `"+"` implicitly type `const char*` and not `std::string`? also why can a `const char*` be implicitly cast into `const std::string` but not `std::string`? – rjc810 Jul 20 '21 at 21:14
  • @rjc810 You're missing that it's `const std::string&` and `std::string&`, that is to say references. – Nathan Pierson Jul 20 '21 at 21:18
  • 2
    @rjc810 `"+"` is a string literal, its type is `const char[2]`, which *decays* into a `const char*` in some contexts. `std::string` has a non-`explicit` constructor that accepts a `const char*`, so you can pass a `const char[N]` into a `(const) std::string` or `const string&` variable/parameter, but not to a non-const `std::string&` reference. If you want `"+"` to be a string, use `contains(opmap, string("+"))` or `using std::literals::string_literals; contains(opmap, "+"s)` instead – Remy Lebeau Jul 20 '21 at 21:23
  • @RemyLebeau Thanks for the precise clarifications ;) – TonySalimi Jul 20 '21 at 21:24
  • 4
    @RemyLebeau `contains(opmap, string("+"))` would have the same problem where you can't bind a prvalue to a non-const reference, wouldn't it? You'd still have to change the function signature, at which point `"+"` itself would work. – Nathan Pierson Jul 20 '21 at 21:29
  • @NathanPierson yes, it would have the same problem – Remy Lebeau Jul 20 '21 at 21:31