Overload math operators [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why is my log in the std namespace?
Based on Overload a C++ function according to the return value, I did the following experiment:
#include <cmath>
class myType
{
private:
double value;
myType(double value) : value(value) {}
public:
myType& operator= (const myType& other) {
if (this != &other) value = other.value;
return *this;
}
static myType test(double val) { return myType(val); }
friend std::ostream& operator<<(std::ostream& target, const myType& A);
};
std::ostream& operator<<(std::ostream& target, const myType& A){
target << A.value;
return target;
}
class asin {
private:
double value;
public:
asin(double value)
: value(std::asin( (value<-1.0) ? -1.0 : (value>1.0?1.0:value) ))
{}
operator double() { return value; }
operator myType() { return myType::test(value); }
};
int main(int argc, char *argv[])
{
myType d = asin(1.0);
std::cout << d << std::endl;
return 0;
}
which resulted in
error: ‘myType::myType(double)’ is private
on the first line in main(). A bit more experimenting showed me that this works fine and as expected when I change the classname asin to Asin (or anything else for that matter). So apparently, I'm not allowed to call my class asin, while the act of defining it (and not using it) does not give me any warning/error.
Now I know all of this is bad practice, so don't flame me for that. I ask this purely out of academic interest: why can't I call my class asin, or acos or atan or anything like that? I was under the impression that cmath hid everything in the std-namespace, so that defining this class in the global namespace would not give rise this particular problem.
Can anyone explain what's going on?

asin is a defined as global function in c++ standard library, and also defined in math library, (so you even dont have to use std::)
If you try using unamed namespace then you would get 'use of `asin' is ambiguous' error.
And named namespace solves your issue.

For some IDEs, for example Visual Studio, you do not even need to include cmath. It has these functions already defined in the global namespace. Try to exclude cmath and you will see that asin() is still defined.

Related

Argument Dependent Lookup and stream operators overloading

I have a library which expose some sort of container struct in which I want to collect diverse generic type of data which might be from the same namespace of the library as well as data from the std namespace such as array or tuple or pairs.
This container has a print_all method which will invoke operator<< for all the elements in the container. Such an operator is supposed to be provided by the user of the library.
Testing the library, I am using different template parameters for T, but I do not care too much about what is being printed by the print_all method. For the test purpose I care only that an example character is being printed no matter which T is being tested. Actually, I my real code I am using Google Test Framework and the behavior of the method under test is really asserted to be the same for every data type provided.
I tried to provide both a generic version of operator<< and two specific versions of it. You can see them in between the #if directive. None of the two compilation branches compiles correctly, most likely because of some violation of the König lookup rules. But anyway what I want to do should be easily possible somehow. What am I missing?
Here is the example code:
#include <algorithm>
#include <iostream>
#include <vector>
namespace my
{
template<typename DataType>
struct Container
{
void print_all( std::ostream& os ) const
{
std::for_each(std::begin(data),
std::end(data),
[&os](const DataType& value)
{
os << value;
});
}
std::vector<DataType> data;
};
namespace test
{
struct Data
{
std::byte data[4];
};
using Array = std::array<std::byte,4>;
#if 0
template<typename T>
std::ostream& operator<<(std::ostream& os, const T& data)
{
return os << 'X';
}
#else
std::ostream& operator<<(std::ostream& os, const Data& data)
{
return os << 'X';
}
std::ostream& operator<<(std::ostream& os, const Array& data)
{
return os << 'X';
}
#endif
void run()
{
// Test with custom data
{
Container< Data> container;
container.data.resize(1);
container.print_all( std::cout );
}
// Test with std data
{
Container< Array> container;
container.data.resize(1);
container.print_all( std::cout );
}
}
} // namespace test
} // namespace my
int main()
{
my::test::run();
return 0;
}
ADL looks into the namespaces associates with the arguments.
using Array = std::array<std::byte,4>;
this type test::Array is an alias. The namespaces associated with it for the purpose of ADL is std. test is not associated with it. ADL will only look in std. You are not permitted to add operators to std; if you violate that, your program is ill-formed, no diagnostic required. ADL cannot help you, because it only helps people who own the namespace(s) associated with the arguments.
Any << you want to support in std needs to be in namespace my, defined before your print_all function.
Your code for Data looks to me like it works, I assume your question was just poorly written, as it implies os <<Data does not work. If I am wromg amd it doesn't work, it is because of some typo; ADL works fine on structs, but not on aliases. In the future, please include complete error messages when code doesn't work.

Overload Class Instance Variable

I've been looking for this for a bit and haven't had any luck. May be that I'm searching for the wrong words, or perhaps it's an unusual request (Or simply not doable).
Regardless, my question: I want to be able to use an instance of a class... well, here's a very simple example:
class attribute
{
float value;
float min;
float max;
}
attribute attr1;
attr1.value = 5.0f;
Now, basically, I want to use attr1 as if I'm calling
attr1.value
So when I, say,
std::cout << attr1 << std::endl;
It would print 5.0 (Or just 5).
Thanks!
You need to implement
std::ostream& operator<<(std::ostream& os, attribute const& att)
{
os << att.value;
return os; // this is how you "chain" `<<`
}
Either permit att.value through public, friendship, or write a function.
Another alternative would be to build a cast operator to float:
class attribute
{
public:
operator float() const
{
return value;
}
private:
/*the rest of your class here*/
But this could introduce unexpected ambiguities.
Finally, if you want attribute to behave like a numeric type, then you can overload more operators as you see fit. For example, to overload +=, you could write
template<typename Y>
attribute& operator+=(const Y& p)
{
value += p;
return *this;
}

Friend name resolving scope in C++

This is legacy code that likely worked in era 3.2 or 2.8 g++, but no longer. It does still compile under microsoft C/C++ optimizing compiler v.17. The code has also been trimmed down from the original to isolate the salient issue.
in function +=, error: 'to_every' was not declared in this scope
class Matrix {};
class ElementWiseConst
{
public:
ElementWiseConst(const Matrix& m){}
};
class ElementWise : public ElementWiseConst
{
public:
ElementWise(const ElementWise&);
ElementWise(Matrix& m) : ElementWiseConst(m) {}
void operator += (const double val);
friend ElementWise to_every(Matrix& m) { return m; }
};
Matrix& operator += (Matrix& m, const double val) {
to_every(m) += val;
return m;
}
Is this an implicit conversion or scoping that microsoft is incorrectly allowing?
to_every is defined inside of ElementWise and thus can only be found via ADL. The compiler will look at the arguments provided and use its associated namespaces and classes to find the name to_every. The associate classes of Matrix is Matrix itself and its associated namespace is the global namespace (assuming it was declared there). ElementWise needs to be an associated class, thus to_every cannot be found.
To get this to work you can:
Define to_every outside of the class.
Make ElementWise an associated class by making it a template argument (#sehe):
template<class T>
class ADLMatrix {};
using Matrix = ADLMatrix<class ElementWise>;

C++ expected constructor, destructor, or type conversion before '&' token

I got this error expected constructor, destructor, or type conversion before'&'token when I did the operator oveloading. The errors occured in the last 8 lines of fixed.cpp I am not sure what I missed. Any help is appreciated.
This is fixed.hpp
#ifndef FIXED_HPP_
#define FIXED_HPP_
typedef float value_type ;
class fixed
{
public:
fixed();
fixed(value_type integer, value_type fraction);
fixed(double val);
void as_string();
value_type integer();
value_type fraction();
value_type value();
//~fixed();
fixed& operator+=(fixed other);
static const int places=4;
static const int places10=10000;
private:
value_type integer_;
value_type fraction_;
value_type value_;
};
fixed operator+(fixed a, fixed b);
#endif
This is fixed.cpp:
#include "fixed.hpp"
#include <iostream>
#include <ostream>
#include <stdexcept>
#include <string>
#include <algorithm>
using namespace std;
fixed::fixed():integer_(0), fraction_(0), value_(0){}
fixed::fixed(value_type integer, value_type fraction):integer_(integer), fraction_(fraction)
{try
{
if (fraction_ <0)
throw invalid_argument("Invalid argument. Must be positive.");
}
catch (exception& e)
{
cout <<"\n"<< e.what() << std::endl;
}
while (fraction_>= places10)
{
if(int(fraction_)%10 >=5 && fraction_< (places10*10) )
fraction_=int(fraction_/10+1);
else
fraction_ =int(fraction_/10);
}
value_ = integer_*places10 + fraction_;
}
fixed::fixed(double val):integer_(int (val)), fraction_( (val- int(val))*places10)
{ if (val <0)
{ val = val*(-1);
if ( int(val*places10*10)%10>=5)
fraction_ = (fraction_*(-1) +1)*(-1);
}
else
{
if (int(val*places10*10)%10>=5)
fraction_ = fraction_ +1;
}
value_ = integer_*places10 + fraction_;
}
void fixed::as_string()
{ string str;
string str2;
while( (int(integer_)/10) >=0 and int(integer_)>0 )
{
str.push_back(int(integer_)%10 + 48);
integer_ = integer_/10;
//cout<<str<<endl;
}
//cout<<"String format: "<<str<<endl;
reverse(str.begin(), str.end());
//cout<<"Reversed format: "<<str<<endl;
str.push_back('.');
//cout<<"New string: "<<str<<endl;
while( (int(fraction_)/10 )>=0 and int(fraction_)>0)
{
str2.push_back(int(fraction_)%10 + 48);
fraction_ = fraction_/10;
//cout<<str<<endl;
}
//cout<<"String format: "<<str<<endl;
reverse(str2.begin(), str2.end());
str.append(str2);
cout<<"String representation: "<<str<<endl;
}
value_type fixed::value()
{
return value_;
}
value_type fixed::integer()
{
return integer_;
}
value_type fixed::fraction()
{
return fraction_;
}
fixed& fixed::operator+=(fixed other) // error
{ value_ += other.value();
return *this;
}
fixed operator+(fixed a, fixed b) //error
{ a+=b;
return a;}
Your code has lots of problems. Main problem is below:
fixed is a member of namespace std; you are declaring the same name class and having an evil using namespace std; in your code.
Few other points:
Always, make a practice of not using namespace std at global
scope. Put std:: prefix if needed or put using inside the
function scope.
fixed::operator+=(Fixed), should be fixed::operator+=(const
Fixed&); otherwise it will make unnecessary copy.
Above comment is true for operator+(fixed a, fixed b) also and
moreover, it does a += b, which is wrong. It should be plain a +
b equivalent
Clang provides the following error, which should make it more obvious what is going on:
fixed.cpp:90:1: error: reference to 'fixed' is ambiguous
fixed& fixed::operator+=(fixed other) // error
^
./fixed.hpp:6:11: note: candidate found by name lookup is 'fixed'
class fixed
^
/usr/include/c++/4.2.1/bits/ios_base.h:950:3: note: candidate found by name lookup is 'std::fixed'
fixed(ios_base& __base)
^
This is a classic example of why you shouldn't use using namespace std;, you're causing something called namespace pollution by having the same identifiers in the same namespace (since everything from std was pulled in).
First of all, pull in parts of the std namespace only when and if you need them by using std::something;. Or better yet, learn to appreciate the std::, it will make your life a lot easier when you get better at C++ which lives and breathes its standard library.
Second of all, a lot of your code is catastrophic when style is considered, not to mention the bad practices. You're introducing things like:
fixed& operator+=(fixed other);
There is a lot of problems with this, but the most prominent one is the lack of constness and the fact you're actually passing the instance of the class by value, invoking the copy constructor and making an unnecessary duplicate. The reason you need to use const is more of a programmer's safety issue and good practice. You see, you only need to read the incoming value to formulate an answer, a return of the operator. Therefore, making it immutable enables you to safely calculate the result and return it.
fixed& operator+=(const fixed& other); // preferably call *other* rhs (righthandside)
When you remove the using namespace std; or change the name of your class altogether, your initial problems will go away. But there's a lot of things wrong with your operator overloads. Specifically, how you take in parameters, how you return them and managing the situation to do only the things that actually need doing (evading unnecessary copies and temporaries).

Is there any obvious drawback to use a no assignment swap?

I was implementing (for training purpose) a Bubble Sort template function:
template<typename iterInput,
typename predicate>
void BubbleSort(iterInput first1,iterInput last1,predicate func)
{
bool swapped(false);
do
{
swapped = false;
iterInput begin = first1;
iterInput beginMinus = first1;
++begin;
for (;begin != last1; begin++,beginMinus++)
{
if (func(*beginMinus,*begin) )
{
std::swap(*beginMinus,*begin);
swapped = true;
}
}
}
while(swapped);
}
When I have realized that this function will not work for class with no assignment operator, like this one (forgive me for the bad name):
class NoCopyable
{
public:
explicit NoCopyable(int value) : value_(value) {}
NoCopyable(const NoCopyable& other) : value_(other.value_) {}
~NoCopyable() {}
bool operator<(const NoCopyable& other) { return value_ < other.value_; }
void setValue(int value) { value_ = value; }
std::ostream& print(std::ostream& os) const { return os << value_; }
private:
NoCopyable& operator=(const NoCopyable& other);
int value_;
};
std::ostream& operator<<(std::ostream& os, const NoCopyable& obj)
{
return obj.print(os);
}
struct PrintNoCopyable
{
void operator()(const NoCopyable& noCopyable) { std::cout << noCopyable << '\n'; }
};
The compiler raises this error Error 1 error C2248: 'NoCopyable::operator =' : cannot access private member declared in class 'NoCopyable'
So, I have slightly modify the code using instead of the std::swap function my version of the swap function, here is the code:
template<typename T1,
typename T2>
void noAssignmentSwap(T1& t1,T2& t2)
{
T1 temp(t1);
t1.~T1();
new (&t1) T1(t2);
t2.~T2();
new (&t2) T2(temp);
}
The code compiles and gives the right result. However I am not completely sure, I remember a Sutter's article that suggest you to avoid playing with the objects life time. The article just warns you by playing with fire without actually giving you any real reason. I can see problem in exception safety if the copy constructor of T1 or T2 can throw. However there is the same problem in the standard version if the assignment operator is allowed to throw.
Here the question, can you see any possible drawbacks in this version of swap?
Cheers
Apart from anything else, if a class does not have an assignment operator, its designer probably did not intend it to be swapped. If they did that, they probably disabled copy construction too, so your new swap function still won't work.
As for your assertion that Standard Library containers do not need assignment - that is true so long as you don't want to actually do anything useful with them. Does this code compile for you?
#include <vector>
using namespace std;
struct A {
private:
void operator=( const A &);
};
int main() {
vector <A> v;
v.push_back( A() );
v[0] = A(); // assignment needed here
}
I think it won't.
The difference is that when the assignment operator fails, you still have the same number of objects.
If you destroy one object and fail to create a new one, one object is lost! If it was part of a container, the container's state is probably also invalid.
You need a copy ctor instead of an assignment operator, but the two are sufficiently similar that at least in a typical case, you'll have both or you'll have neither. IOW, I don't think this generally accomplishes much.
I'd class it right along side the xor-swap trick: interesting, but generally useless.
It might be confusing to a future maintainer of the code.