admin管理员组

文章数量:1123152

The following piece of code compiles fine

#include <iostream>
#include <map>
#include <memory>

using namespace std;

class child {
    public:
    child(std::string name,uint32_t age) : name(name),age(age){
    }
    std::string name;
    uint32_t age;
};

class parent {
    public:
    uint32_t age;
    parent(std::string name){
        age = 10;
    }
    std::map<uint32_t, std::shared_ptr<child>> child_by_age;
    std::map<std::string, std::shared_ptr<child>> child_by_name;

    child& operator[](const uint32_t& num){
        return *(child_by_age[num]);
    }

    child& operator[](const std::string& n){
        return *(child_by_name[n]);
    }

    void addChild(const child& ch){
        auto ch_obj = std::make_shared<child>(ch);
        child_by_age.emplace(ch.age, ch_obj);
        child_by_name.emplace(ch.name, ch_obj);
    }
};

class top {
    public:
    parent p1;
    top():p1("p1"){
        p1.addChild(child("c0",0));
        p1.addChild(child("c1",1));
    }
    void run(){
        p1["c0"].name = "name";
        p1[0].name = "name1";
    }
};

int main(){
    top t;
    t.run();
    return 0;
}

But the moment I add following conversion operator

   operator uint32_t() const{
        return age;
    }

I am getting the following error

   operator_overload.cpp: In member function ‘void top::run()’:
operator_overload.cpp:50:11: error: ambiguous overload for ‘operator[]’ (operand types are ‘parent’ and ‘const char [3]’)
         p1["c0"].name = "name";
           ^
operator_overload.cpp:50:11: note: candidate: operator[](long int, const char*) <built-in>
operator_overload.cpp:28:12: note: candidate: child& parent::operator[](const string&)
     child& operator[](const std::string& n){
            ^~~~~~~~

I am not sure to understand why the compiler complains on subscript operator when I add conversion operator

The following piece of code compiles fine

#include <iostream>
#include <map>
#include <memory>

using namespace std;

class child {
    public:
    child(std::string name,uint32_t age) : name(name),age(age){
    }
    std::string name;
    uint32_t age;
};

class parent {
    public:
    uint32_t age;
    parent(std::string name){
        age = 10;
    }
    std::map<uint32_t, std::shared_ptr<child>> child_by_age;
    std::map<std::string, std::shared_ptr<child>> child_by_name;

    child& operator[](const uint32_t& num){
        return *(child_by_age[num]);
    }

    child& operator[](const std::string& n){
        return *(child_by_name[n]);
    }

    void addChild(const child& ch){
        auto ch_obj = std::make_shared<child>(ch);
        child_by_age.emplace(ch.age, ch_obj);
        child_by_name.emplace(ch.name, ch_obj);
    }
};

class top {
    public:
    parent p1;
    top():p1("p1"){
        p1.addChild(child("c0",0));
        p1.addChild(child("c1",1));
    }
    void run(){
        p1["c0"].name = "name";
        p1[0].name = "name1";
    }
};

int main(){
    top t;
    t.run();
    return 0;
}

But the moment I add following conversion operator

   operator uint32_t() const{
        return age;
    }

I am getting the following error

   operator_overload.cpp: In member function ‘void top::run()’:
operator_overload.cpp:50:11: error: ambiguous overload for ‘operator[]’ (operand types are ‘parent’ and ‘const char [3]’)
         p1["c0"].name = "name";
           ^
operator_overload.cpp:50:11: note: candidate: operator[](long int, const char*) <built-in>
operator_overload.cpp:28:12: note: candidate: child& parent::operator[](const string&)
     child& operator[](const std::string& n){
            ^~~~~~~~

I am not sure to understand why the compiler complains on subscript operator when I add conversion operator

Share Improve this question edited 6 hours ago Yksisarvinen 22.1k5 gold badges33 silver badges65 bronze badges asked 6 hours ago KPathakKPathak 492 bronze badges 5
  • Include your toolchain (msvc, gcc, whatever) in your post. Oh ,and btw. you're missing #include <string> from your include stack. The use of std::string dictates its presence. – WhozCraig Commented 6 hours ago
  • 1 Re: "the moment I add following conversion operator" -- add it to what and where? Show the code that doesn't work, not the code that works. And remove code that doesn't contribute to showing the problem. I'll bet you could remove three-quarters of the code from the question and still show the problem. – Pete Becker Commented 6 hours ago
  • 1 But the moment I add following conversion operator -- It has been over 20 minutes since you were asked to post the code that fails, thus in danger of having the question closed. Don't run off when posting a question, since you may be asked to provide more details, or else the question may be closed or downvoted. You have two classes, child and parent, that have age defined. So where did you add this conversion operator? – PaulMcKenzie Commented 6 hours ago
  • I mean when I add the conversion operator function in the "parent" class. – KPathak Commented 5 hours ago
  • If you are asking us about an error, why not show us the code that produces this error? – Drew Dormann Commented 5 hours ago
Add a comment  | 

1 Answer 1

Reset to default 1

1["asdf"] is completely valid C++ code, equivalent to "asdf"[1] (because reasons). Thus, compiler is confused what do you want to do:

  1. convert p1 to uint32_t and use that as subscript to "c0"
  2. convert "c0" to std::string and use user-defined operator[].

Both options require one conversion, so both are considered equally good.

There are 3 possible solutions :

  1. Make you conversion operator explicit - this will make it impossible to consider for implicit conversions like here and the conversion can only happen when you use static_cast explicitly: static_cast<std::uint32_t>(p1)
   explicit operator uint32_t() const{
        return age;
    }
  1. Use actual std::string instead of char[]:
        p1["c0"s].name = "name";
        // or
        p1[std::string{"c0"}].name = "name";
  1. Provide operator[] that accepts a char[] instead - this will mean there is no conversion required and compiler can unambiguously choose this overload:
    template <std::size_t N>
    child& operator[](const char (&arr)[N] ){
        return operator[](std::string{arr});
    }

Note that this requires accepting array by reference, since array-to-pointer decay is also a conversion.

本文标签: cCompilation issue when conversion operator is addedStack Overflow