3

Consider the following stripped-down example of a (templated) C++ structure for square matrices (it doesn't need to be templated for the problem to occur):

#include <array>
#include <complex>
using namespace std;

double conj (double &x) { return x; };

template <typename T, int N>
struct matrix: array<T,N*N> {
    void conj() {
        for (int ij=0; ij<100; ++ij) {
            T z = (*this)[ij];
            (*this)[ij] = conj(z);
        }
    }
};

int main() {
    matrix<double,10> a;
    a.conj();
    return 0;
}

I want to implement a method that performs matrix complex conjugation, using the name .conj() to coincide with the naming system used in the < complex > library. However, I get the following error:

$ g++ example.cpp -std=c++11
example.cpp: In instantiation of ‘void matrix<T, N>::conj() [with T = double; int N = 10]’:
example.cpp:19:12:   required from here
example.cpp:12:26: error: no matching function for call to ‘matrix<double, 10>::conj(double&)’
      (*this)[ij] = conj(z);
                          ^
example.cpp:12:26: note: candidate is:
example.cpp:9:10: note: void matrix<T, N>::conj() [with T = double; int N = 10]
     void conj() {
          ^
example.cpp:9:10: note:   candidate expects 0 arguments, 1 provided

The compiler doesn't seem to recognize the function conj(double&) called inside the method of the same name, and defined before the structure. Instead, it tries to call the method conj().

Why isn't the compiler able to resolve this naming conflict, and what would be the solution that preserves the naming? Of course, if I change the name of the method to something different to conj, the code compiles and runs normally.

FreeQuark
  • 213
  • 1
  • 8
  • 3
    Use the [scope operator](http://en.wikipedia.org/wiki/Scope_resolution_operator), Luke: `(*this)[ij] = ::conj(z);` – FoggyDay Aug 26 '14 at 17:18
  • In your main function you are calling a.conj() instead of conj(double &x). When you have two or more functions with the same name, C++ will make functions calls based on the # of input parameters. You should call them according to their parameters. – Juniar Aug 26 '14 at 18:25

1 Answers1

9

The member function hides functions of the same name in a wider scope.

Use the qualified name ::conj to refer to the function in the global namespace.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Such a simple and elegant solution. Thank you, Mike! I never thought the scope operator :: could be used with nothing on its left hand side. – FreeQuark Aug 26 '14 at 17:24
  • 1
    @helvio: With nothing on the left-hand side, it specifies the global namespace (which doesn't have a name). – Mike Seymour Aug 26 '14 at 17:26
  • Following the error, does that means the compiler thinks this is a recursive function call? If that is the case, this would have lead into an infinite loop. – Juniar Aug 26 '14 at 18:34
  • @Juniar: No, the compiler can't find an overload taking `double` (since it's hidden by the member function), so fails to compile it. If both functions had the same signature, then you'd get a recursive call rather than a compile error. – Mike Seymour Aug 26 '14 at 22:53
  • That make sense, so it never get called anyway. However, it looks like a run time error, since both functions are declared within the same class. – Juniar Aug 27 '14 at 02:06
  • @Juniar: No, the question clearly states the compile-time error. They're not both declared within the same class; one is a member of `matrix`, while the other is a non-member in the global namespace. – Mike Seymour Aug 27 '14 at 10:41