4

The following code (simplified from a problem occuring with this NamedType library, see https://github.com/joboccara/NamedType/issues/61)

template<typename T>
struct PreIncrementable {
    constexpr T& operator++()
    {
        ++static_cast<T &>(*this).get();
        return static_cast<T &>(*this);
    }
};

template<typename T>
struct PostIncrementable {
    constexpr T operator++(int)
    {
        ++static_cast<T &>(*this).get();
        return static_cast<T &>(*this);
    }
};

struct test : PostIncrementable<test>, PreIncrementable<test> {
    constexpr int &get() {
        return m_int;
    }

    constexpr int get() const {
        return m_int;
    }

    int m_int{};
};

int main() {
    test t;
    t++;
}

will compile and run as expected with clang. But compiling with g++ -std=c++17 inc_gcc.cpp -o gcc results in

inc_gcc.cpp: In function ‘int main()’:
inc_gcc.cpp:34:6: error: request for member ‘operator++’ is ambiguous
   34 |     t++;
      |      ^~
inc_gcc.cpp:4:18: note: candidates are: ‘constexpr T& PreIncrementable<T>::operator++() [with T = test]’
    4 |     constexpr T& operator++()
      |                  ^~~~~~~~
inc_gcc.cpp:13:17: note:                 ‘constexpr T PostIncrementable<T>::operator++(int) [with T = test]’
   13 |     constexpr T operator++(int)
      |                 ^~~~~~~~

This seems like a bug of gcc to me, since exactly one of those signatures matches a pre-increment. Am I correct? Is this a known bug?

GCC version info:

g++ (GCC) 11.1.0

PS: Adding

    using PostIncrementable<test>::operator++;
    using PreIncrementable<test>::operator++;

to test seems to fix it.

n314159
  • 4,990
  • 1
  • 5
  • 20
  • fyi clang recons the code has no effect - look at generated - live - https://godbolt.org/z/qn9zsoEWo – Richard Critten Oct 12 '21 at 12:03
  • @RichardCritten You need to do something with `t` otherwise everything is optimized out with `-O3`, see e.g. https://godbolt.org/z/f77E6cden – Holt Oct 12 '21 at 12:05
  • That is only because `t` is unused, hence it is optimized away. Add `return t.get();` and it does something. – n314159 Oct 12 '21 at 12:05
  • Thanks to all above - just realised and done as suggested. – Richard Critten Oct 12 '21 at 12:05
  • 1
    Also doing `t.operator++();` or `t.operator++(42);` gets all the compilers complaining. – Richard Critten Oct 12 '21 at 12:14
  • For me gcc is right, `operator++` are in both base classes so it is ambiguous (checking argument is done after). Replace `operator++` by `func` and you would have same issue. – Jarod42 Oct 12 '21 at 13:29

0 Answers0