Overloading operator+ with pointers - c++

I'm working on a project on polymorphism in C++ and I have lots of pointers. I need to overload the operator +, so that I can write the following expression naturally:
c=a+b;
with a,b and c being declared as:
A *a,*b,*c;
The basic overloading definitions I know are
A &operator+(const A& a)
A &operator=(const A& a)
but I get the following errors:
invalid initialization of non-const reference of type 'A&' from an rvalue of type 'A* const'
invalid operands of types 'A*' and 'A*' to binary 'operator+'
How should I write the overloaded operator so that I can call it naturally?

I know that my following suggestion is probably not what you want, but for the sake of completeness I tried to find a solution with a template wrapper class around pointers which would permit overloading operator+. I wondered what exactly the combination of lookup rules, template arguments and type conversion could achieve. It turns out that the "natural" use of operator+ seems impossible, but an explicit call works. Here is my code:
/** A wrapper class around arbitrary pointer types */
template<class TPtr> class MyPtrT
{
public:
TPtr ptr;
MyPtrT(const TPtr p = 0) :ptr(p)
{}
};
/** A plus operator on all MyPtrTs */
template<class T>
const MyPtrT<T>&
operator+(const MyPtrT<T> &l, const MyPtrT<T> &r)
{
return l;
}
MyPtrT<int *> mp1, mp2, mp3;
int *ip;
Ok, what works with these declarations?
// This works (template type explicit) ...
mp3 = operator+<int *>(ip, ip);
// ... and this works (of course,
// arguments match template declaration) ...
mp3 = mp1 + mp2;
And what doesn't (with gcc 4.8.3)?
mp3 = mp1 + ip;
The error is:
smartpointplus.cpp:33:12: error: no match for ‘operator+’ (operand types are ‘MyPtrT<int*>’ and ‘int*’)
mp3 = mp1 + ip;
^
smartpointplus.cpp:33:12: note: candidate is:
smartpointplus.cpp:13:1: note: template<class T> const MyPtrT<T>& operator+(const MyPtrT<T>&, const MyPtrT<T>&)
operator+(const MyPtrT<T> &l, const MyPtrT<T> &r)
^
smartpointplus.cpp:13:1: note: template argument deduction/substitution failed:
smartpointplus.cpp:33:14: note: mismatched types ‘const MyPtrT<T>’ and ‘int*’
I'm not quite sure why the compiler doesn't construct a MyPtrT from the int* argument. It does see the proper function. Perhaps something is wrong with my ctor?
mp3 = operator+(ip, ip);
The error message is similar. The template function is considered but the compiler cannot convert the arguments.
smartpointplus.cpp:36:24: error: no matching function for call to ‘operator+(int*&, int*&)’
mp3 = operator+(ip, ip);
^
smartpointplus.cpp:36:24: note: candidate is:
smartpointplus.cpp:13:1: note: template<class T> const MyPtrT<T>& operator+(const MyPtrT<T>&, const MyPtrT<T>&)
operator+(const MyPtrT<T> &l, const MyPtrT<T> &r)
^
smartpointplus.cpp:13:1: note: template argument deduction/substitution failed:
smartpointplus.cpp:36:24: note: mismatched types ‘const MyPtrT<T>’ and ‘int*’
mp3 = operator+(ip, ip);
It's a bit sad that operator+(ip, ip) (automatically trying to deduce the template type) doesn't work. That limits usability ;-). One would have to templatize all functions using that operator in order to avoid providing the template type explicitly for every call. The infix notation below, by contrast, doesn't even consider the template operator:
mp3 = ip + ip;
The error message is short:
smartpointplus.cpp:38:13: error: invalid operands of types ‘int*’ and ‘int*’ to binary ‘operator+’
mp3 = ip + ip;
I always thought that infix and function style notation of operator calls are just, well, notational differences, but apparently they also change the lookup rules.
tl;dr: What the OP wanted (an infix plus operation with pointer arguments) doesn't work even with a template wrapping class, afaict.

The assignment operator is a special member method (see http://en.cppreference.com/w/cpp/language/operators and http://en.cppreference.com/w/cpp/language/as_operator) and C++ dont allow operator override over pointers after his first standard (before, some implementations allow to do that).

Related

C++ "error: use of overloaded operator '*' is ambiguous" with seemingly only one match

I am trying to use custom operators in C++ for a project I am working on. This project uses the ROCm/HIP stack (so, under the hood, the clang compiler).
Here's the error message:
src/zlatrd.cpp:359:32: error: use of overloaded operator '*' is ambiguous (with operand types 'magmaDoubleComplex' (aka 'hip_complex_number<double>') and 'float')
alpha = tau[i] * -0.5f * value;
~~~~~~ ^ ~~~~~
./include/magma_operators.h:190:1: note: candidate function
operator * (const magmaDoubleComplex a, const double s)
^
./include/magma_operators.h:183:1: note: candidate function
operator * (const magmaDoubleComplex a, const magmaDoubleComplex b)
^
./include/magma_operators.h:437:1: note: candidate function
operator * (const magmaFloatComplex a, const float s)
^
./include/magma_operators.h:430:1: note: candidate function
operator * (const magmaFloatComplex a, const magmaFloatComplex b)
^
It seems to me that it is not ambiguous; it should select the third candidate function, as the argument is a float.
Here is the type definition for the hip_complex_number template:
template <typename T>
struct hip_complex_number
{
T x, y;
template <typename U>
hip_complex_number(U a, U b)
: x(a)
, y(b)
{
}
template <typename U>
hip_complex_number(U a)
: x(a)
, y(0)
{
}
hip_complex_number()
: x(0)
, y(0)
{
}
};
I notice it has an implicit constructor that will convert a float, but I assumed that given a candidate function that matches the type exactly (not including the const modifier), that it would obviously select that function overload over those which require an implicit cast.
EDIT: Also, I know that by default C/C++ convert from float/double to each other if the function is defined in that way, so 'matches the type exactly' was definitely not the right wording.
Can someone explain why C++ thinks this is ambiguous?
EDIT: People have asked for the definition of magmaFloatComplex, which is hip_complex_number<float>
Please note that I don't know anything about the library that these types are from. I will explain the ambiguity purely based on the information in the question.
The first and third overload are ambiguous.
In the overload operator * (const magmaDoubleComplex a, const double s) a floating-point promotion from float to double is required in the second argument.
In the overload operator * (const magmaFloatComplex a, const float s) a user-defined conversion to an unrelated type from magmaDoubleComplex to magmaFloatComplex is required. This conversion is possible, because of the non-explicit converting constructor
template <typename U>
hip_complex_number(U a)
The corresponding other parameters don't need any conversion aside from potentially lvalue-to-rvalue conversions or user-defined conversion to the same type, which are considered exact match.
Exact match is better than either user-defined conversion to an unrelated type or floating-point promotion, meaning that each overload has one parameter that is better than the other one's and one that is worse than the other one's.
Overload resolution is ambiguous if not at least one overload has all parameters not worse than all other overload's parameters. Therefore the two mentioned overloads are ambiguous here.
The second overload has exact match in the first argument and requires a user-defined conversion to unrelated type in the second argument, which is again possible because of the converting constructor mentioned above. However the floating-point promotion of the first overload is considered better than a user-defined conversion to unrelated type and therefore the second overload looses against the first one in overload resolution, but would be ambiguous with the third one as well.
The fourth overload is worse than all the others, because it requires user-defined conversions to unrelated types in both parameters.
Note that if overload 3 would be selected as expect in your question, it would result in an error, because the converting constructor chosen for magmaFloatComplex will try to initialize the x member which is of type float with a magmaDoubleComplex, which (at least based on your shown code) doesn't have a conversion operator to float.

Why does not std::nullptr_t work with std::cout in C++?

I learned about std::nullptr_t that is the type of the null pointer literal, nullptr.
Then I made small program :
#include <iostream>
int main()
{
std::nullptr_t n1;
std::cout<<n1<<endl;
return 0;
}
Here, nullptr_t is data type and n1 is variable and I'm trying to print the value of variable. But, Compiler give an error:
prog.cpp: In function 'int main()':
prog.cpp:6:11: error: ambiguous overload for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'std::nullptr_t')
std::cout<<n1<<endl;
Why does not std::nullptr_t work with std::cout in C++? What am I wrong here?
operator<< for output streams has overloads for multiple different types of pointers, but not std::nullptr_t 1. This means that the compiler cannot determine which overload to call, because any of the overloads accepting a pointer are equally good. (For example, it accepts char const * for C-style strings, and also void const *, which will output the raw pointer value.)
One option to fix this would be to define your own overload that forces the use of the void const * overload:
std::ostream & operator<<(std::ostream &s, std::nullptr_t) {
return s << static_cast<void *>(nullptr);
}
Or have it do something else:
std::ostream & operator<<(std::ostream &s, std::nullptr_t) {
return s << "nullptr";
}
Notes:
1 As pointed out in the comments, there is an overload accepting std::nullptr_t in C++17, so this will cease to be an issue if you are using a conforming C++17 implementation.
endl needs std::-qualification -- but you should use '\n' here anyway. (std::endl is only a good idea when you need the stream flushed.)

Member function pointer issue with standard library methods

This question is spawned from
Passing a member function pointer to an overloaded class method into a template function.
You need not read that to understand this question. Probably both the questions will have the same answer.
I am getting compiler error for below simple code.
#include<set>
template<typename Return, typename T>
T ReceiveFuncPtr (Return (T::*Method)(const int&))
{
T obj; // Found and declared an object of actual container class
(obj.*Method)(1); // Some processing
return obj; // Returned that container class object with RVO
}
int main ()
{
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
}
The error is interesting:
In function 'int main()':
error: no matching function for call to 'ReceiveFuncPtr(<unresolved overloaded function type>)'
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
^
note: candidate is:
note: template<class Return, class T> T ReceiveFuncPtr(Return (T::*)(const int&))
T ReceiveFuncPtr (Return (T::*Method)(const int&))
^
note: template argument deduction/substitution failed:
note: mismatched types 'const int&' and 'std::initializer_list<int>'
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
^
note: mismatched types 'const int&' and 'std::set<int>::const_iterator {aka std::_Rb_tree_const_iterator<int>}'
note: mismatched types 'const int&' and 'std::set<int>::const_iterator {aka std::_Rb_tree_const_iterator<int>}'
note: mismatched types 'const int&' and 'std::set<int>::value_type&& {aka int&&}'
note: couldn't deduce template parameter 'Return'
If you look at the notes closely then it appears that compiler is matching all the other methods except the right one! In this case compiler should have matched insert(const std::set<int>::value_type&) aka const int&. If I change the ReceiveFuncPtr() to match some other overload, it will again fail by skipping that overload.
To debug this situation, I created handcrafted version of std::set. But that compiles fine:
template<typename T, typename T2 = void>
struct MySet
{
std::pair<T,bool> insert (const T& i) { return std::pair<T,bool>(T(),true); }
std::pair<T,bool> insert (T&& i) { return std::pair<T,bool>(T(),true); }
void insert (std::initializer_list<T> i) { return false; }
}
int main ()
{
ReceiveFuncPtr(&MySet<int>::insert); // OK
}
After surfing, I came across this post:
What are the rules for function pointers and member function pointers to Standard functions?
Though it's related , it doesn't solve problem.
Question: Why member function substitution fails in case of standard library method when the the same thing passes for handwritten class method?
Update:
After looking at the correct answer, I am sure that insert cannot be used. The only way would be ugly typecasting which is an overkill for this problem.
One elegant solution is to use std::set<int>::emplace<const int&> which has only templated version unlike insert which has mix of template and non-template versions.
Call the function as below:
ReceiveFuncPtr(&std::set<int>::emplace<const int&>);
Above compiles fine.
The problem isn't with the insert functions you showed in MySet. The problem is with one of the ones you omitted. Specifically:
template< class InputIt >
void insert( InputIt first, InputIt last );
From [temp.deduct.call]:
When P is a function type, pointer to function type, or pointer to member function type:
— If the argument is an overload set containing one or more function templates, the parameter is treated
as a non-deduced context.
Since &std::set<int>::insert is precisely such an overload set, the parameter is a non-deduced context and cannot be resolved. Your example of MySet does not contain a function template overload for insert, which is why it works fine. If you add one, you'll see that it will also fail to compile.

Passing a member function pointer to an overloaded class method into a template function [duplicate]

This question is spawned from
Passing a member function pointer to an overloaded class method into a template function.
You need not read that to understand this question. Probably both the questions will have the same answer.
I am getting compiler error for below simple code.
#include<set>
template<typename Return, typename T>
T ReceiveFuncPtr (Return (T::*Method)(const int&))
{
T obj; // Found and declared an object of actual container class
(obj.*Method)(1); // Some processing
return obj; // Returned that container class object with RVO
}
int main ()
{
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
}
The error is interesting:
In function 'int main()':
error: no matching function for call to 'ReceiveFuncPtr(<unresolved overloaded function type>)'
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
^
note: candidate is:
note: template<class Return, class T> T ReceiveFuncPtr(Return (T::*)(const int&))
T ReceiveFuncPtr (Return (T::*Method)(const int&))
^
note: template argument deduction/substitution failed:
note: mismatched types 'const int&' and 'std::initializer_list<int>'
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
^
note: mismatched types 'const int&' and 'std::set<int>::const_iterator {aka std::_Rb_tree_const_iterator<int>}'
note: mismatched types 'const int&' and 'std::set<int>::const_iterator {aka std::_Rb_tree_const_iterator<int>}'
note: mismatched types 'const int&' and 'std::set<int>::value_type&& {aka int&&}'
note: couldn't deduce template parameter 'Return'
If you look at the notes closely then it appears that compiler is matching all the other methods except the right one! In this case compiler should have matched insert(const std::set<int>::value_type&) aka const int&. If I change the ReceiveFuncPtr() to match some other overload, it will again fail by skipping that overload.
To debug this situation, I created handcrafted version of std::set. But that compiles fine:
template<typename T, typename T2 = void>
struct MySet
{
std::pair<T,bool> insert (const T& i) { return std::pair<T,bool>(T(),true); }
std::pair<T,bool> insert (T&& i) { return std::pair<T,bool>(T(),true); }
void insert (std::initializer_list<T> i) { return false; }
}
int main ()
{
ReceiveFuncPtr(&MySet<int>::insert); // OK
}
After surfing, I came across this post:
What are the rules for function pointers and member function pointers to Standard functions?
Though it's related , it doesn't solve problem.
Question: Why member function substitution fails in case of standard library method when the the same thing passes for handwritten class method?
Update:
After looking at the correct answer, I am sure that insert cannot be used. The only way would be ugly typecasting which is an overkill for this problem.
One elegant solution is to use std::set<int>::emplace<const int&> which has only templated version unlike insert which has mix of template and non-template versions.
Call the function as below:
ReceiveFuncPtr(&std::set<int>::emplace<const int&>);
Above compiles fine.
The problem isn't with the insert functions you showed in MySet. The problem is with one of the ones you omitted. Specifically:
template< class InputIt >
void insert( InputIt first, InputIt last );
From [temp.deduct.call]:
When P is a function type, pointer to function type, or pointer to member function type:
— If the argument is an overload set containing one or more function templates, the parameter is treated
as a non-deduced context.
Since &std::set<int>::insert is precisely such an overload set, the parameter is a non-deduced context and cannot be resolved. Your example of MySet does not contain a function template overload for insert, which is why it works fine. If you add one, you'll see that it will also fail to compile.

Setting a std::function variable to refer to the std::sin function

I've got a question about how to properly use the new C++11 std::function variable. I've seen several examples from searching the Internet, but they don't seem to cover the usage case I'm considering. Take this minimum example, where the function fdiff is an implementation of the finite forward differencing algorithm defined in numerical.hxx (which isn't the problem, I just wanted to give a contextual reason why I'd want to take an arbitrary function and pass it around).
#include <functional>
#include <iostream>
#include <cmath>
#include "numerical.hxx"
int main()
{
double start = 0.785398163;
double step = 0.1;
int order = 2;
std::function<double(double)> f_sin = std::sin;
std::cout << fdiff(start, step, order, f_sin) << std::endl;
return 0;
}
Attempting to compile the above program gives me the error (in clang++)
test.cpp:11:32: error: no viable conversion from '<overloaded function type>' to
'std::function<double (double)>'
std::function<double(double)> f_sin = std::sin;
^ ~~~~~~~~
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/functional:2048:7: note:
candidate constructor not viable: no overload of 'sin' matching
'nullptr_t' for 1st argument
function(nullptr_t) noexcept
^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/functional:2059:7: note:
candidate constructor not viable: no overload of 'sin' matching 'const
std::function<double (double)> &' for 1st argument
function(const function& __x);
^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/functional:2068:7: note:
candidate constructor not viable: no overload of 'sin' matching
'std::function<double (double)> &&' for 1st argument
function(function&& __x) : _Function_base()
^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/functional:2092:2: note:
candidate template ignored: couldn't infer template argument '_Functor'
function(_Functor __f,
^
1 error generated.
or from g++
test.cpp: In function ‘int main()’:
test.cpp:11:45: error: conversion from ‘<unresolved overloaded function type>’ to non-scalar type ‘std::function<double(double)>’ requested
As I understand the problem, it's because std::sin is implemented as a template class in the standard library, but I can't seem to figure out what I need to do to give enough of a specialization to get a function reference. I've also tried various things like using the new auto keyword, using &std::sin to get a pointer, etc., but they all give me the same type of error.
std::sin is an overloaded function: you must disambiguate which std::sin overload you mean:
std::function<double(double)> f_sin = (double(*)(double))&std::sin;
There are some cases where the compiler can disambiguate overloaded functions (e.g., if f_sin was of type double(*)(double), the cast would not be required). However, this is not one of those cases.
With lambda you will be always on safe side:
std::function<double(double)> f_sin = [](double arg) -> double { return std::sin(arg); };
Actually you can do better, if you can change fdiff or it is already accepting template parameter - not just std::function<double(double)>:
auto f_sin = [](double arg) -> double { return std::sin(arg); };
std::cout << fdiff(start, step, order, f_sin) << std::endl;
[UPDATE] This answer is new version, previous advice to use function template specialization was incorrect, since std::sin is not function template but set of overloaded functions.