Ambiguity by making overloaded operator function-const - why?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • abendstund@gmail.com

    Ambiguity by making overloaded operator function-const - why?

    Hi,


    I have the following code and trouble with ambiguity due to operator
    overloading..

    The code is also at http://paste.nn-d.de/441

    snip>>

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

    using namespace std;


    class ConfigItem;
    typedef map<wstring, ConfigItemConfi gMap;

    class ConfigItem {

    public:
    ConfigItem() { type=NONE; s[0]=0; }


    ConfigItem(cons t wchar_t *str) {
    type=STRING;
    wcscpy(s, str);
    }
    operator const wchar_t*() const {
    return s;
    }
    wchar_t operator[](int pos) const {
    return (operator const wchar_t*())[pos];
    }


    ConfigItem& operator[](const wchar_t *option) {
    return operator[](wstring(option ));
    }
    ConfigItem& operator[](const wstring &option) {
    switch (type) {
    case MAP: return (*cm)[option];
    default: return *this;
    }
    }

    private:
    enum {
    NONE,
    INT,
    STRING,
    MAP,
    } type;

    wchar_t s[512];
    ConfigMap *cm;
    };


    int main() {
    if (wchar_t(Config Item()[0]) == L'\0')
    cout << "works as expected";

    return 0;
    }

    <<snap



    If I compile it using g++ 4.1.2, I get:

    test.cpp: In function 'int main()':
    test.cpp:53: error: ISO C++ says that these are ambiguous, even though
    the worst conversion for the first is better than the worst conversion
    for the second:
    test.cpp:24: note: candidate 1: wchar_t ConfigItem::ope rator[](int)
    const
    test.cpp:32: note: candidate 2: ConfigItem& ConfigItem::ope rator[]
    (const std::wstring&)
    test.cpp:53: error: ISO C++ says that these are ambiguous, even though
    the worst conversion for the first is better than the worst conversion
    for the second:
    test.cpp:24: note: candidate 1: wchar_t ConfigItem::ope rator[](int)
    const
    test.cpp:29: note: candidate 2: ConfigItem& ConfigItem::ope rator[]
    (const wchar_t*)



    On which path does ISO C++/the compiler deduct the second
    candidates?? Now for the really (to me) weird part:

    If I remove the function const from wchar_t operator[](int pos) const
    so it reads

    wchar_t operator[](int pos) {

    above code works as expected and no ambiguity error is shown, the
    following does also work

    const wchar_t operator[](const int pos) {


    It is just the function const that provokes the ambiguity - why?



    Many thx for an insightful reply, I spent hours on this and don't
    really have a clue, why making an overloaded operator function-const
    opens paths to the ambiguity shown.

    Btw, this is not the full code, just the minimal part to make the
    mistake happen



    Thanks much,
    Christian Müller
  • Eric Pruneau

    #2
    Re: Ambiguity by making overloaded operator function-const - why?


    <abendstund@gma il.coma écrit dans le message de news:
    ef9c8d94-fe62-4991-a0b7-ac7a62d51cc1...le groups.com...
    Hi,


    I have the following code and trouble with ambiguity due to operator
    overloading..

    The code is also at http://paste.nn-d.de/441

    snip>>

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

    using namespace std;


    class ConfigItem;
    typedef map<wstring, ConfigItemConfi gMap;

    class ConfigItem {

    public:
    ConfigItem() { type=NONE; s[0]=0; }


    ConfigItem(cons t wchar_t *str) {
    type=STRING;
    wcscpy(s, str);
    }
    operator const wchar_t*() const {
    return s;
    }
    wchar_t operator[](int pos) const {
    return (operator const wchar_t*())[pos];
    }


    ConfigItem& operator[](const wchar_t *option) {
    return operator[](wstring(option ));
    }
    ConfigItem& operator[](const wstring &option) {
    switch (type) {
    case MAP: return (*cm)[option];
    default: return *this;
    }
    }

    private:
    enum {
    NONE,
    INT,
    STRING,
    MAP,
    } type;

    wchar_t s[512];
    ConfigMap *cm;
    };


    int main() {
    if (wchar_t(Config Item()[0]) == L'\0')
    cout << "works as expected";

    return 0;
    }

    <<snap



    If I compile it using g++ 4.1.2, I get:

    test.cpp: In function 'int main()':
    test.cpp:53: error: ISO C++ says that these are ambiguous, even though
    the worst conversion for the first is better than the worst conversion
    for the second:
    test.cpp:24: note: candidate 1: wchar_t ConfigItem::ope rator[](int)
    const
    test.cpp:32: note: candidate 2: ConfigItem& ConfigItem::ope rator[]
    (const std::wstring&)
    test.cpp:53: error: ISO C++ says that these are ambiguous, even though
    the worst conversion for the first is better than the worst conversion
    for the second:
    test.cpp:24: note: candidate 1: wchar_t ConfigItem::ope rator[](int)
    const
    test.cpp:29: note: candidate 2: ConfigItem& ConfigItem::ope rator[]
    (const wchar_t*)



    On which path does ISO C++/the compiler deduct the second
    candidates?? Now for the really (to me) weird part:

    If I remove the function const from wchar_t operator[](int pos) const
    so it reads

    wchar_t operator[](int pos) {

    above code works as expected and no ambiguity error is shown, the
    following does also work

    const wchar_t operator[](const int pos) {


    It is just the function const that provokes the ambiguity - why?



    Many thx for an insightful reply, I spent hours on this and don't
    really have a clue, why making an overloaded operator function-const
    opens paths to the ambiguity shown.

    Btw, this is not the full code, just the minimal part to make the
    mistake happen



    Thanks much,
    Christian Müller



    ok first try this :

    if (wchar_t(Config Item()[1]) == L'\0') // 0 changed by 1
    cout << "works as expected";

    you gonna see that it work. That is because using 0 could be interpreted as
    a NULL pointer and that is the reason the compiler is considering the
    function with a wchar_t *.

    you can do :

    int zero = 0;
    if (wchar_t(Config Item()[zero]) == L'\0') // 0 changed by 1
    cout << "works as expected";

    than it will work.

    Now for the const thing.
    First, the return value is never used in argument deduction, so adding a
    const to the return value does not change anything, but it does if you make
    the function const.


    This should work fine

    const ConfigItem c;
    if (wchar_t(c[0]) == L'\0')
    cout << "works as expected";

    cause c is const and therefore no ambiguity here since the function is
    const.




    Comment

    • abendstund@gmail.com

      #3
      Re: Ambiguity by making overloaded operator function-const - why?

      ok first try this :
      >
      if (wchar_t(Config Item()[1]) == L'\0') // 0 changed by 1
      cout << "works as expected";
      >
      you gonna see that it work. That is because using 0 could be interpreted as
      a NULL pointer and that is the reason the compiler is considering the
      function with a wchar_t *.
      >
      you can do :
      >
      int zero = 0;
      if (wchar_t(Config Item()[zero]) == L'\0') // 0 changed by 1
      cout << "works as expected";
      >
      than it will work.
      >
      Thanks for your answer, but at least the first part is bogus, first
      statement is not true - it does not matter if i use 0 or 1, the
      ambiguity is even present if I do:

      if (wchar_t(Config Item()[int(0)]) == L'\0') // explicit cast to int
      cout << "works as expected";

      Now for the const thing.
      First, the return value is never used in argument deduction, so adding a
      const to the return value does not change anything, but it does if you make
      the function const.
      >
      This should work fine
      >
      const ConfigItem c;
      if (wchar_t(c[0]) == L'\0')
      cout << "works as expected";
      >
      cause c is const and therefore no ambiguity here since the function is
      const.
      Ok this works, but I was under the impression that making a function
      const just makes the compiler enforce my intention to not change any
      values outside of the scope of this function.. you say it does make a
      difference, but in what way. After all, I am allowed to call the
      const function from a non-const ConfigItem. So why is it ambiguous?

      Regards and thx,
      Christian

      Comment

      • James Kanze

        #4
        Re: Ambiguity by making overloaded operator function-const - why?

        On Jun 1, 10:38 pm, abendst...@gmai l.com wrote:
        I have the following code and trouble with ambiguity due to
        operator overloading..
        The code is also athttp://paste.nn-d.de/441
        snip>>
        #include <iostream>
        #include <string>
        #include <map>
        using namespace std;
        class ConfigItem;
        typedef map<wstring, ConfigItemConfi gMap;
        class ConfigItem {
        public:
        ConfigItem() { type=NONE; s[0]=0; }
        ConfigItem(cons t wchar_t *str) {
        type=STRING;
        wcscpy(s, str);
        }
        operator const wchar_t*() const {
        return s;
        }
        wchar_t operator[](int pos) const {
        return (operator const wchar_t*())[pos];
        }
        >
        ConfigItem& operator[](const wchar_t *option) {
        return operator[](wstring(option ));
        }
        ConfigItem& operator[](const wstring &option) {
        switch (type) {
        case MAP: return (*cm)[option];
        default: return *this;
        }
        }
        private:
        enum {
        NONE,
        INT,
        STRING,
        MAP,
        } type;
        wchar_t s[512];
        ConfigMap *cm;
        };
        int main() {
        if (wchar_t(Config Item()[0]) == L'\0')
        cout << "works as expected";
        return 0;
        }
        <<snap
        If I compile it using g++ 4.1.2, I get:
        >
        test.cpp: In function 'int main()':
        test.cpp:53: error: ISO C++ says that these are ambiguous, even though
        the worst conversion for the first is better than the worst conversion
        for the second:
        test.cpp:24: note: candidate 1: wchar_t ConfigItem::ope rator[](int)
        const
        test.cpp:32: note: candidate 2: ConfigItem& ConfigItem::ope rator[]
        (const std::wstring&)
        test.cpp:53: error: ISO C++ says that these are ambiguous, even though
        the worst conversion for the first is better than the worst conversion
        for the second:
        test.cpp:24: note: candidate 1: wchar_t ConfigItem::ope rator[](int)
        const
        test.cpp:29: note: candidate 2: ConfigItem& ConfigItem::ope rator[]
        (const wchar_t*)
        On which path does ISO C++/the compiler deduct the second
        candidates??
        For the operator[], the compiler considers two arguments, the
        object on which it is going to be called (the argument which
        becomes the this pointer), and the index argument. In your
        expression, ConfigItem()[0], you have a (non-const) ConfigItem,
        and a constant integral expression evaluating to 0. Both
        operator[]( int ) const and operator[]( wchar_t* ) can be
        called. For the first argument, the second is the better match,
        because the first requires a qualifier conversion. For the
        second argument, the first is a better match, because it is an
        exact match. The result is that the call is ambiguous.
        Now for the really (to me) weird part:
        If I remove the function const from wchar_t operator[](int
        pos) const so it reads
        wchar_t operator[](int pos) {
        above code works as expected and no ambiguity error is shown,
        Yes. Because now, you have a better match for the second
        argument, and the first two are equal (both exact matches).
        the following does also work
        const wchar_t operator[](const int pos) {
        This is the same as the above.
        It is just the function const that provokes the ambiguity - why?
        Because it means that calling the function on a non-const object
        requires a qualifier conversion.
        Many thx for an insightful reply, I spent hours on this and
        don't really have a clue, why making an overloaded operator
        function-const opens paths to the ambiguity shown.
        It *is* sometimes surprising. But frankly, I'd wonder about so
        many overloads. What does [] mean on an object of your class?
        Off hand, I'd say that if you have [] whose return type differs
        in more than just const, then you have operator overload abuse:
        if there's a natural meaning for [], then that will exclusively
        determine the return type, and if there's not, then you
        shouldn't use [].

        --
        James Kanze (GABI Software) email:james.kan ze@gmail.com
        Conseils en informatique orientée objet/
        Beratung in objektorientier ter Datenverarbeitu ng
        9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

        Comment

        • James Kanze

          #5
          Re: Ambiguity by making overloaded operator function-const - why?

          On Jun 2, 4:44 am, abendst...@gmai l.com wrote:
          ok first try this :
          if (wchar_t(Config Item()[1]) == L'\0') // 0 changed by 1
          cout << "works as expected";
          you gonna see that it work. That is because using 0 could be interpretedas
          a NULL pointer and that is the reason the compiler is considering the
          function with a wchar_t *.
          you can do :
          int zero = 0;
          if (wchar_t(Config Item()[zero]) == L'\0') // 0 changed by 1
          cout << "works as expected";
          than it will work.
          Thanks for your answer, but at least the first part is bogus, first
          statement is not true - it does not matter if i use 0 or 1, the
          ambiguity is even present if I do:
          if (wchar_t(Config Item()[int(0)]) == L'\0') // explicit cast to int
          cout << "works as expected";
          Which still has the 0. Use 1 instead of 0, and the ambiguity
          disappears. Use anything but a constant integral expression,
          and the ambiguity disappears.

          --
          James Kanze (GABI Software) email:james.kan ze@gmail.com
          Conseils en informatique orientée objet/
          Beratung in objektorientier ter Datenverarbeitu ng
          9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

          Comment

          Working...