C/C++ Overload functions by dimension of vector

AI Thread Summary
The discussion revolves around the ambiguity encountered in C++ when defining overloaded functions named "negate" for different vector types. The primary issue arises when trying to call the two versions of the function—one for a vector of OP objects and another for a vector of vectors of OP objects—leading to a compilation error due to the compiler's inability to distinguish between them. The term "neg" is mentioned but left unclear, prompting further questions about its definition.Participants highlight that the ambiguity may stem from the use of "using namespace std," which can introduce conflicts with standard library functions like std::negate. Suggestions include avoiding this directive and only including necessary headers to prevent such issues. The conversation also touches on the design considerations in object-oriented programming, emphasizing the importance of defining classes for different vector dimensions to avoid confusion and ensure clarity in operations. The discussion concludes with insights into how different compilers handle these definitions, reinforcing the need for careful naming and organization in code to avoid ambiguity.
Pete5876
Messages
7
Reaction score
0
C++:
vector<OP> negate (vector<OP> a) {
    a.insert(a.begin(), neg);
    return a;
}

vector<vector<OP>> negate (vector<vector<OP>> a) {
    for (int i=0; i<a.size(); i++)
        a[i] = negate(a[i]); // reference to 'negate' is ambiguous?
    return a;
}

OP is an enum here. Why can't C++ distinguish between these two? One function takes a two-dimensional vector of OP whereas the other one takes a three-dimensional vector of OP. I can't flatten that 3D vector because it's elements aren't of the same size.
 
Technology news on Phys.org
On line 2, what is "neg"?
Once I resolved that, it compiled for me.

Code:
#include <vector>
using namespace std;

class OP {
public:
   int n1;
};

vector<OP> negate (vector<OP> a) {
   for(int i=0; i<a.size(); i++)
      a[i].n1 = -a[i].n1;
   return a;
}

vector<vector<OP>> negate (vector<vector<OP>> a) {
   for(int i=0; i<a.size(); i++)
      a[i] = negate(a[i]);
   return a;
}
 
C++:
#include <iostream>
#include<vector>
using namespace std;

vector<int> negate (vector<int> a) {
    a.insert(a.begin(), -1);
    return a;
}

vector<vector<int>> negate (vector<vector<int>> a) {
    for (int i=0; i<a.size(); i++)
        a[i] = negate(a[i]); // reference to 'negate' is ambiguous?
    return a;
}

int main() {
    vector<vector<int>> r = {{3,4,5,6},{4,4,5,6,7,4}};
    r=negate(r);
    return 0;
}

I provided a more complete and simpler code. In line 12 the compilers (Dev, Visual Studio and several online C++ compilers), they're all find that "ambiguous". But since a is of type <vector<vector<int>> then a must be of type vector<int>, right? Negate function adds a -1 value at the beginning of every vector.
 
Your code works for me.
Are you creating a vector<int> somewhere else in your build?
 
It's a complete code. Try pasting the code from my last post into https://www.onlinegdb.com/online_c++_compiler or any other IDE and the error comes out the same every time "main.cpp:12:16: error: reference to ‘negate’ is ambiguous".
 
There is also a std::negate, which is probably found via argument dependent lookup? Try replacing the "using namespace std" by "using std::vector".
 
I'm using MS Visual Studio 2022.
Vector.png
 
BTW, whatever compiler version onlinegdb uses, it also compiles if you don't include iostream. I think the lessons here are 1) avoid "using namespace std;" and 2) don't include what you don't use.
 
vis_insita said:
I think the lessons here are 1) avoid "using namespace std;" and 2) don't include what you don't use.
Excellent advice.
 
  • Like
Likes Vanadium 50 and pbuk
  • #10
CLHEP, when faced with this, decided they wanted different classes for 2-vectors, 3-vectors and 4-vectors. One reason is that you do different things with them: the norm of a 4-vector is not the same as a 3-vector. Part of the reason is that it is not clear what is meant when you combine them: when you add a 2-vector to a 3-vector, how do you promote it? Set the z-component to zero? What's specila about z?

I would say the trick to OOP is to make sure your objects are neither too general nor too specific. Other people have found an arbitrarily dimensioned vector to be too general.
 
  • #11
.Scott said:
I'm using MS Visual Studio 2022.
It depends on how the standard library implementers organize their header files. gcc apparently declares std::negate in a header used by std::string, which is included via iostream. You can get this information from the compiler output on onlinegdb:
main.cpp:19:7: error: reference to ‘negate’ is ambiguous
19 | r=negate(r);
| ^~~~~~
In file included from /usr/include/c++/11/string:48,
from /usr/include/c++/11/bits/locale_classes.h:40,
from /usr/include/c++/11/bits/ios_base.h:41,
from /usr/include/c++/11/ios:42,
from /usr/include/c++/11/ostream:38,
from /usr/include/c++/11/iostream:39,
from main.cpp:2:
The latest gcc version also pulls std::negate in together with the vector header. (It can also depend on the language standard used.) So, other than renaming "negate" there is no way around removing the using directive in this example, in which it is also completely unnecessary.

EDIT:
vis_insita said:
There is also a std::negate, which is probably found via argument dependent lookup?
I just realized that std::negate is a struct not a function. Also it can be found by ordinary name lookup, since the unqualified name is already visible thanks to the using directive. At any rate, ADL has nothing to do with it.
 
Last edited:
Back
Top