Consider the following class:
template<class a>
class c
{
public:
int x = 0;
// not really templated
friend constexpr auto operator +( int const left,
c const & a ) noexcept
{
return c{ left + x };
}
};
How does one move the function body without declaring it in the outer scope? e.g. pseudo:
template<class a>
friend constexpr auto c<a>::operator +( int const left,
c const & a ) noexcept
{
return c{ left + x };
}
The first snippet of OP:
class c
{
public:
int x = 0;
friend constexpr auto operator +( int const left,
c const & a ) noexcept
{
return c{ left + x };
}
};
It shows a free function (operator) that is inline defined in class c as friend.
This is not a member function of class c although it may look so on the first glance.
(If it would be a member function it would be a ternary operator+ but there doesn't exist one in C++ nor can it be overloaded.)
The second snippet of OP:
friend constexpr auto c::operator +( int const left,
c const & a ) noexcept
{
return c{ left + x };
}
It is wrong for two reasons:
friend doesn't make sense. (friend to what?)
If it's a free function - scope c:: doesn't make sense.
The friendship of functions cannot be declared outside of the resp. class.
If this would be allowed everybody could declare friendship of functions everywhere which accesses the private members of classes. This would make the sense of private members somehow useless.
(Imagine a safe with an electronic lock and a key pad where the password is written on the door.)
(Original image by Binarysequence - Own work, CC BY-SA 4.0, Link)
Nevertheless, friend functions (and operators) can be defined non-inline, of course.
The following sample shows how:
#include <iostream>
// forward declaration of class c
class c;
// forward declaration of operator +
constexpr auto operator+(int, c const&) noexcept;
// the class c
class c {
// make operator + a friend to grant access to private members
friend constexpr auto operator+(int, c const&) noexcept;
private:
int x;
public:
c() = default;
constexpr c(int x): x(x) { }
int get() const { return x; }
};
// the operator +
constexpr auto operator+(int lhs, c const &rhs) noexcept
{
return c(lhs + rhs.x);
}
// show it in action:
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(c a(123));
DEBUG(std::cout << (234 + a).get() << '\n');
}
Output:
c a(123);
std::cout << (234 + a).get() << '\n';
357
Live Demo on coliru
This is similar when applied to templates (although the syntax is a bit more tricky):
#include <iostream>
// forward declaration of class c
template <typename T>
class c;
// forward declaration of operator +
template <typename T>
constexpr auto operator+(int, c<T> const&) noexcept;
// the class c
template <typename T>
class c {
friend constexpr auto operator+<>(int, c<T> const&) noexcept;
private:
T x;
public:
c() = default;
constexpr c(T x): x(x) { }
int get() const { return x; }
};
// the operator +
template <typename T>
constexpr auto operator+(int lhs, c<T> const &rhs) noexcept
{
return c(lhs + rhs.x);
}
// show it in action:
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(c<int> a(123));
DEBUG(std::cout << (234 + a).get() << '\n');
}
Output:
c<int> a(123);
std::cout << (234 + a).get() << '\n';
357
Live Demo on coliru
More about inline friend functions:
SO: friend AND inline method, what's the point ?
SO: c++ implementing friend/inline functions (similar question)
SO: Nonmember friend function is always inline (similar question)
The closest you can get is to define the function in a source file such that its out-of-class declaration is not visible to (other) clients. (You would not be able to have its return type be deduced in that case.) In C++20, you can do something very similar by not exporting the friend from a module.
It has been suggested that what you want should be achievable with a differently qualified definition:
constexpr auto ::operator +( int const left,
c const & a ) noexcept
{
return c{ left + x };
}
The otherwise redundant scope resolution operator would cause the definition to “not count” for name lookup, but GCC and Clang currently give it other interpretations: Clang does let ordinary lookup find the function (and issues a warning in the global scope case), while GCC rejects it entirely.
Related
I have a program that has a base class Value with multiple subclasses (e.g. IntValue) that inherit from Value. Each of these classes have constructors that accept one or more parameters. Here is example code showing what I'd like to be able to do:
#include <iostream>
class Value {
public:
Value() {}
virtual void print(std::ostream& os) const {}
};
class IntValue: public Value {
public:
IntValue(int val): val_(val) {}
void print(std::ostream& os) const override { os << val_; }
private:
int val_;
};
class VariableValue: public Value {
public:
VariableValue(const std::string& name): name_(name) {}
void print(std::ostream& os) const override { os << name_; }
private:
const std::string name_;
};
void emit_add(const Value& lhs, const Value& rhs, std::ostream& os) {
lhs.print(os);
os << " + ";
rhs.print(os);
os << std::endl;
}
template <class ValueType>
void emit_add(const ValueType& lhs, const ValueType& rhs, std::ostream &os) {
lhs.print(os);
os << " + ";
rhs.print(os);
os << std::endl;
}
int main() {
// all these work
emit_add<IntValue>(12, 13, std::cout); // implicit constructors
emit_add<VariableValue>(std::string("x"), std::string("y"), std::cout); // implicit constructo\
rs
emit_add(VariableValue(std::string("x")), IntValue(1), std::cout); // implicit upcasting
// this doesn't
emit_add(std::string("x"), 13, std::cout); // implicit constor + implicit upcasting
return -1;
}
When I try to compile using clang 9.1.0, I get the following error:
test.cpp:47:3: error: no matching function for call to 'emit_add'
emit_add(std::string("x"), 13, std::cout); // implicit constor + implicit upcasting
^~~~~~~~
test.cpp:25:6: note: candidate function not viable: no known conversion from 'std::string' (aka
'basic_string<char, char_traits<char>, allocator<char> >') to 'const Value' for 1st
argument
void emit_add(const Value& lhs, const Value& rhs, std::ostream& os) {
^
test.cpp:33:6: note: candidate template ignored: deduced conflicting types for parameter
'ValueType' ('std::__1::basic_string<char>' vs. 'int')
void emit_add(const ValueType& lhs, const ValueType& rhs, std::ostream &os) {
^
1 error generated.
My understanding is that the compiler is failing to call the implicit constructor for VariableValue AND THEN upcast it to type Value, but it can clearly do both individually.
Is it possible to force the compiler to do this?
A VariableValue is a Value (because inheritance is an "is a" relationship), but Value is not an VariableValue (the "is a" relationship of inheritance is one-way).
What I'm trying to say is that if you have a VariableValue object, you can easily go up the inheritance chain to get a Value object (or reference of it). But you can't go the other way, down the inheritance chain from a Value object, without being explicit about it.
You need to explicitly construct a VariableValue object and pass it to your function:
emit_add(VariableValue(x), 13, std::cout);
Consider the following as counter-example:
class Value
{
public:
Value() { }
Value(int) { }
Value(std::string const&) { }
};
emit_add(x, 13, std::cout);
This now would have worked as the compiler sees emit_add accepting two Values and Value having appropriate non-explicit constructors accepting std::string and int.
What C++ does not provide is inferring derived classes from base class according to given arguments, as Some programmer dude denoted already.
You could, though, provide a wrapper to do this work for you:
class Wrapper
{
std::unique_ptr<Value> value;
public:
Wrapper(int n) : value(new IntValue(n)) { }
Wrapper(std::string) : value(new VariableValue(n)) { }
friend std::ostream& operator<<(std::ostream& s, Wrapper const& w)
{
w.value->print(s);
return s;
}
};
If that's really better than specifying the types directly (as Some programmer dude did) is a matter of taste. On the other hand, as defined above (with operator<<), you now can do:
void emit_add(Wrapper const& lhs, Wrapper const& rhs, std::ostream& os)
{
os << lhs << " + " << rhs << std::endl;
}
which is a little more comfortable as well...
Another approach could be an overloaded template:
void emit_add(Value const& x, Value const& y, std::ostream& os);
template <typename TX, typename TY>
void emit_add(TX&& x, TY&& y, std::ostream& os)
{
emit_add
(
static_cast<Value const&>(TheValue<TX>(std::forward<TX>(x))),
static_cast<Value const&>(TheValue<TY>(std::forward<TY>(y))),
os
);
}
The casts above are necessary as otherwise, the template itself would be a better match and the non-template would not be selected, resulting in endless recursion. I converted the concrete values into a template for:
template <typename T>
class TheValue : public Value
{
public:
TheValue(T&& t)
: val_(std::forward<T>(t))
{ }
void print(std::ostream& os) const override
{
os << val_;
}
private:
T val_;
};
If this default pattern does not match your concrete needs for a specific type, you can specialise it for that type to suite your needs.
If you still need the original type names, you can alias them:
using IntValue = TheValue<int>;
Finally, if it is solely for printing out, you can do it directly, circumventing the Value class entirely:
template <typename TX, typename TY>
void emit_add(TX&& x, TY&& y, std::ostream& os)
{
std::cout << std::forward<TX>(x) << " + " << std::forward<TY>(y) << std::endl;
}
If you now have some custom types you want to print, just provide an operator<< overload for, such as for the following point example:
template <typename T>
class Point
{
T m_x, m_y;
public:
// constructors, calculations, ... (whatever you might need/find useful)
friend ostream& operator<<(ostream& s, Point const& p)
{
s << '(' p.m_x << ", " << p.m_y << ')';
}
};
Side note: The friend operator as above is convenient for your own data types (it still defines a free standing function), just if you did:
template <typename T>
ostream& operator<<(ostream& s, Point<T> const& p)
{
s << '(' p.x() << ", " << p.y() << ')';
}
outside the class (you still can declare it friend inside; if you don't or can't, you cannot use private members, of course, so you rely on the public interface as demonstrated above, assuming x and y are the public getters).
Lets say i have a class, for which i want to overload an operator based on an enum type:
#include <iostream>
enum class option : char { normal, do_something_stupid };
class foo
{
public:
int i;
explicit foo(int a=0) : i(a) {};
/* overload operator '+=' based on 'option' */
template<option E = option::normal>
void operator+=(const foo& f) { i += f.i; }
};
/* explicit specialization for operator += */
template<> void foo::operator+=<option::do_something_stupid>(const foo& f)
{ i += (f.i +1000); }
int main()
{
foo f1(1), f2(2);
f1 += f2;
std::cout << "\nf1 = " << f1.i;
f1.operator+=<option::do_something_stupid>(f2);
std::cout << "\nf1 = " << f1.i;
std::cout << "\n";
return 0;
}
This builds clean (ignoring the fact that it really does something pretty dump) both on g++ and clang++.
What if i want to overload the '<<' operator the same way? A similar approach does not seem to work:
#include <ostream>
#include <iostream>
enum class option : char { normal, do_something_stupid };
class foo
{
public:
int i;
explicit foo(int a=0) : i(a) {};
template<option E = option::normal>
friend std::ostream& operator<<(std::ostream& o, const foo& f)
{ o << f.i; return o; }
};
template<> std::ostream&
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
{
o << f.i + 1000;
return o;
}
int main()
{
foo f1(1), f2(2);
std::cout << "\nf1= " << f1;
std::cout << "\nf2= ";
/* this triggers an error with g++ */
std::cout.operator<< <option::do_something_stupid>(f1);
std::cout << "\n";
return 0;
}
According to g++, the call from main to the operator is invalid:
error: no match for ‘operator<’ (operand types are ‘<unresolved overloaded function type>’ and ‘option’)
std::cout.operator<< <option::do_something_stupid>(f1);
clang++ on the other hand, produces a different error message:
lsfov.cc:20:1: error: 'operator<<' cannot be the name of a variable or data member
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
^
lsfov.cc:20:11: error: expected ';' at end of declaration
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
^
;
lsfov.cc:20:12: error: expected unqualified-id
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
^
lsfov.cc:33:15: error: reference to non-static member function must be called
std::cout.operator<< <option::do_something_stupid>(f1);
~~~~~~~~~~^~~~~~~~~~
which goes on listing possible overload of '<<' from the standard library (if i understand correctly), like:
/usr/bin/../lib/gcc/x86_64-redhat-linux/5.3.1/../../../../include/c++/5.3.1/ostream:108:7: note: possible target for call
operator<<(__ostream_type& (*__pf)(__ostream_type&))
^
/usr/bin/../lib/gcc/x86_64-redhat-linux/5.3.1/../../../../include/c++/5.3.1/ostream:117:7: note: possible target for call
operator<<(__ios_type& (*__pf)(__ios_type&))
^
What is going on? Is this kind of operator specialization possible/allowed? If so, what is the proper way to call the operator? Or is clang correct and the definition is ill formed?
I think clang doesn't like the declaration of the friend in relation to the specialisation. Re-ordering them does the trick.
enum class option : char { normal, do_something_stupid };
// forward declare the class and operator
class foo;
template<option E = option::normal>
std::ostream& operator<<(std::ostream& o, const foo& f);
// the class with the declared friend operator
class foo
{
private:
int i;
public:
explicit foo(int a=0) : i(a) {};
template<option E>
friend std::ostream& operator<<(std::ostream& o, const foo& f);
};
// the operator implementations
template<option E>
std::ostream& operator<<(std::ostream& o, const foo& f)
{ o << f.i; return o; }
template<> std::ostream&
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
{
o << f.i + 1000;
return o;
}
In addition, the operator<< used in the main is not a member cout, but rather a global.
int main()
{
foo f1(1), f2(2);
std::cout << "\nf1= " << f1;
std::cout << "\nf2= ";
/* this triggers an error with g++ */
operator<< <option::do_something_stupid>(std::cout, f1);
std::cout << "\n";
return 0;
}
Sample here. g++ is also happy with the code as above.
A note on operators in a non-deduced context. I assume you are using the code here in a greater project of some sort, but if the operator is being used with non-deduced parameters, it is often easier and clearer to implement the functionality in a member method or a free function (using friend as required).
I just tried to make a function that compares 2 objects, but it gives me:
Error: bool Duree::operator==(const Duree&, const Duree&) must take exactly one argument
How can I solve this? Thank you.
Duree.h
#ifndef DEF_DUREE
#define DEF_DUREE
class Duree
{
public:
Duree(int heures = 0, int minutes = 0, int secondes = 0);
bool estEgal(Duree const& b) const;
bool operator==(Duree const& a, Duree const& b);
private:
int m_heures;
int m_minutes;
int m_secondes;
};
#endif
Duree.cpp
#include "Duree.h"
Duree::Duree(int heures, int minutes, int secondes) : m_heures(heures), m_minutes(minutes), m_secondes(secondes)
{
}
bool Duree::estEgal(Duree const& b) const
{
return (m_heures == b.m_heures && m_minutes == b.m_minutes && m_secondes == b.m_secondes);
}
bool operator==(Duree const& a, Duree const& b)
{
return a.estEgal(b);
}
Main.cpp
#include <iostream>
#include "Duree.h"
using namespace std;
int main()
{
Duree fisrt(10, 10, 10), second(15, 20);
if (fisrt == second)
cout << "Les durees sont identiques";
else
cout << "Les durees sont differentes";
return 0;
}
Either you declare operator== as a free function with two arguments:
bool operator==(Duree const& a, Duree const& b);
or as a member function with only one argument:
bool Duree::operator==(Duree const& b);
This is because when you do x == y you are comparing only two objects. If you have a member function there's an implicit "this object" (the one you call operator== on) passed, making it 3 arguments instead of 2.
That being said, from the way you wrote the code I'm guessing you just forgot to put friend in front of the operator== declaration, in the class definition.
Probably useful tip: You can use #pragma once, on compilers that support it (basically every "main" compiler), instead of include guards. :)
Change your prototype to bool operator==(Duree const& rhs); or make it a free function out of class Duree.
Always prefer the binary functions to be NON MEMBER (free) functions. Otherwise you can run into problems if you overload the operator with different types. Consider the following contrived code:
struct Foo {
int x;
bool operator==(Foo const & other) const { return x == other.x; }
};
This should work fine for comparing two Foos together. But it has a problem.
Suppose you also want to compare to an int:
struct Foo {
int x;
bool operator==(Foo const & other) const { return x == other.x; }
bool operator==(int other) const { return x == other; }
};
Now you can compare one way but not the other:
Foo a, b;
...
a == b; // ok
a == 123; // ok
123 == a; // ERROR
As member function the object must be on the right hand side.
Simple, move the int-Foo overloads out of the class, and make two versions, Foo==int and int==Foo? (Note, making them friends declared inside the class can accomplish that too, FWIW, but I'm not showing it here.)
struct Foo {
int x;
bool operator==(Foo const & other) const { return x == other.x; }
};
bool operator==(int other, Foo const& f) { return f.x == other; }
bool operator==(Foo const& f, int other) { return f.x == other; }
So now everything works, right? We have a mix of member and non-member operators.
a == b; // ok
a == 123; // ok
123 == a; // ok
Until Foo starts getting member functions that want to use the operators...
struct Foo {
int x;
bool operator==(Foo const & other) const { return x == other.x; }
void g(int x);
};
bool operator==(int other, Foo const& f) { return f.x == other; }
bool operator==(Foo const& f, int other) { return f.x == other; }
void Foo::g(int x)
{
Foo f = getOtherFoo();
if (f == x) { // ERROR! cannot find operator==(Foo,int)
//...
}
}
It STILL has a problem! Inside members of of Foo, it cannot see the non-member operators because the member one hides them! g() will not compile since it can't compare Foo to int. Moving all of the operators out will resolve it, since then all of the overloads are in the same scope.
(Remember, name-lookup keeps searching outer scopes UNTIL it finds the fist case of the name it is looking for, and then only considers all the names it finds in that scope. Inside g(), it's scope is in the class, and since it finds one version of the operator inside the class (the wrong one), it never looks outside the class for more overloads. But if they are all outside the class, it'll find them all at the same time.)
struct Foo {
int x;
void g(int x);
};
// NON MEMBER
bool operator==(Foo const & lhs, Foo const & rhs) { return lhsx == rhs.x; }
bool operator==(int other, Foo const& f) { return f.x == other; }
bool operator==(Foo const& f, int other) { return f.x == other; }
void Foo::g(int x)
{
Foo f = getOtherFoo();
if (f == x) { // OK now, finds proper overload
//...
}
}
Now, it compiles in all the cases. That's why they say, "Always prefer to make non-member binary operator overloads." Otherwise you can end up with symmetry and hiding problems.
I'm on the same kind of issue.
Worked by putting operator== with two arguments back in main.cpp before the main() ;)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Operator overloading
What causes C++ compiler error: must have argument of class or enumerated type?
I am trying to play a little bit with operator overloading and genericity in C++ and I seem to have 3 little errors when I try to compile. Have a class named Grandeur with template D, and then I inherit 3 classes from this one, named Temps(time), Longueur(size), Vitesse(speed), and I am trying to overload the operators such as when I do Temps+Temps->Temps, Vitesse+Vitesse=Vitesse,Longueur+Longueur->Longueur, Longueur/Time->Vitess etc.
In order not to write 3 times the same functions for the operations of same type, I use templates to utilise the genericity. But I have an error when I try to compile. Here is my code:
typedef double Longueur;
typedef double Temps;
typedef double Vitesse;
template<typename D>
class Grandeur {
protected :
double val; const char* unite;
public :
Grandeur(double qqc) : val(qqc) {}
Grandeur(int qqc) : val(qqc) {}
Grandeur(long qqc) : val(qqc) {}
Grandeur(float qqc) : val(qqc) {}
inline friend D operator+ (const D a, const D b) {
return D (a.val + b.val);
}
inline friend D operator- (const D a, const D b) {
return D (a.val - b.val);
}
inline friend double operator* (const D a, const D b) {
return a.val * b.val;
}
inline friend double operator/ (const D a, const D b) {
return a.val / b.val;
}
inline friend D operator* (D a, const int b) {
return D (a.val * b);
}
inline friend D operator/ (const D a, const int b) {
return D (a.val / b);
}
inline friend ostream& operator<< (ostream& os, D d) {
return os << d.val << d.u;
}
class Temps : public Grandeur<Temps> {
public:
};
class Vitesse : public Grandeur<Vitesse> {
public:
};
class Longueur : public Grandeur<Longueur> {
public:
};
};
inline Longueur operator* (const Vitesse v, const Temps t) {
return Longueur(v.val * t.val);
}
inline Vitesse operator/ (const Longueur l, const Temps t) {
return Vitesse(l.val / t.val);
}
inline Temps operator/ (const Longueur l, const Vitesse v) {
return Temps(l.val / v.val);
}
When I try to compile it says:
g++ essai.cc
In file included from essai.cc:4:0:
grandeurs.h:70:58: error: ‘Longueur operator*(Vitesse, Temps)’ must have an argument of class or enumerated type
grandeurs.h:74:58: error: ‘Vitesse operator/(Longueur, Temps)’ must have an argument of class or enumerated type
grandeurs.h:78:58: error: ‘Temps operator/(Longueur, Vitesse)’ must have an argument of class or enumerated type
The lines 70, 74 and 78 are those with the last 3 functions (the inlines). What can I do?
You're declaring the operators at global scope so the types Vitesse etc are not available to the compiler. Why not move the child classes outside Grandeur<T>'s definition?
EDIT for comment:
You're trying to use the operators with double values, but the implicit conversions are not automatically inherited by your child classes. You'll need to define them in each child and pass the parameters up to the parent template class.
I am learning C++, and learned that int-types are just premade classes. So I thought maybe i should try to create one.
What I want to do basically is a
normal class of int
int x;
x=7;
cout << x;
// Output is 7 on screen.
so similarly...
abc x;
x=7;
cout << x;
What would I put in
class abc{
\\ HERE!!!!!!
};
so I could do this
class SomeClass {
public:
int x;
SomeClass(int x) {
this->x = x;
}
};
int main(int argc, char *argv[]) {
SomeClass s = 5;
cout << s.x << "\n"; // 5
s = 17;
cout << s.x << "\n"; // 17
return 0;
}
But as you can see I have to use s.x to print the value - I just want to use 's'.
I am doing it as an experiment, I don't want to hear about how this method is good or bad, pointless or revolutionary, or can 't be done. I remember once I did it. But only by copying and pasting code that I didn't fully understand, and have even forgotten about.
and learned that int, types, are just premade classes
This is completely false. Still, you have complete control on how your class will behave in expressions, since you can overload (almost) any operator. What you are missing here is the usual operator<< overload that is invoked when you do:
cout<<s;
You can create it like this:
std::ostream & operator<<(std::ostream & os, const SomeClass & Right)
{
Os<<Right.x;
return Os;
}
For more information, see the FAQ about operator overloading.
the << and >> are basically function names. you need to define them for your class. same with the +, -, * and all the other operators. here is how:
http://courses.cms.caltech.edu/cs11/material/cpp/donnie/cpp-ops.html
You need to overload operator<< for your class, like so:
class abc
{
public:
abc(int x) : m_X(x) {}
private:
int m_X;
friend std::ostream& operator<<(std::ostream& stream, const abc& obj);
};
std::ostream& operator<<(std::ostream& os, const abc& obj)
{
return os << obj.m_X;
}
You don't have to friend your operator<< overload unless you want to access protected/private members.
You must define in your class abc cast operator to int and assignment operator from int, like in this template class:
template <class T>
class TypeWrapper {
public:
TypeWrapper(const T& value) : value(value) {}
TypeWrapper() {}
operator T() const { return value; }
TypeWrapper& operator (const T& value) { this->value = value; return *this; }
private:
T value;
};
int main() {
TypeWrapper<int> x;
x = 7;
cout << x << endl;
}
You want to overload the output operator:
std::ostream& operator<< (std::ostream& out, SomeClass const& value) {
// format value appropriately
return out;
}