The code below not compile in gcc 4.7, but compile in VS(9, 10, 11) also follows the gcc output.
#include <iostream>
using namespace std;
class A
{
public:
virtual void M() = 0;
};
class B
{
public:
inline B& operator<<(A &value)
{
value.M();
return *this;
}
};
class C: public A
{
public:
virtual void M()
{
cout << "Hello World" << endl;
}
};
int main()
{
B b;
C c;
b << c; //line not erro
b << C(); //Line with error
return 0;
}
gcc log
$g++ main.cpp -o test main.cpp: In function 'int main()':
main.cpp:36:12: error: no match for 'operator<<' in 'b << C()'
main.cpp:36:12: note: candidates are: main.cpp:14:15: note: B&
B::operator<<(A&) main.cpp:14:15: note: no known conversion for
argument 1 from 'C' to 'A&'
C++ does not allow you to bind a non-const reference to a temporary like you are attempting to do here:
b << C();
// ^^^^ temporary
VS allows you to do this as an "extension", but it is non-standard and therefore non-portable, as you have discovered.
What you need is a const reference in the relevant operator:
inline B& operator<<(const A& value)
// ^^^^^
One way of sorting it out is using C++11 rvalue binding feature.
B& operator<<(A&& value)
{ ... }
as an overload.
Related
error: passing 'const A' as 'this' argument of 'void A::hi()' discards
qualifiers [-fpermissive]
I don't understand why I'm getting this error, I'm not returning anything just passing the reference of the object and that is it.
#include <iostream>
class A
{
public:
void hi()
{
std::cout << "hi." << std::endl;
}
};
class B
{
public:
void receive(const A& a) {
a.hi();
}
};
class C
{
public:
void receive(const A& a) {
B b;
b.receive(a);
}
};
int main(int argc, char ** argv)
{
A a;
C c;
c.receive(a);
return 0;
}
#edit
I fixed it using const correctness but now I'm trying to call methods inside of the same method and I get the same error, but the weird thing is that I'm not passing the reference to this method.
#include <iostream>
class A
{
public:
void sayhi() const
{
hello();
world();
}
void hello()
{
std::cout << "world" << std::endl;
}
void world()
{
std::cout << "world" << std::endl;
}
};
class B
{
public:
void receive(const A& a) {
a.sayhi();
}
};
class C
{
public:
void receive(const A& a) {
B b;
b.receive(a);
}
};
int main(int argc, char ** argv)
{
A a;
C c;
c.receive(a);
return 0;
}
error: passing 'const A' as 'this' argument of 'void A::hello()'
discards qualifiers [-fpermissive]
error: passing 'const A' as 'this' argument of 'void A::world()'
discards qualifiers [-fpermissive]
Your hi method is not declared as const inside your A class. Hence, the compiler cannot guarantee that calling a.hi() will not change your constant reference to a, thus it raises an error.
You can read more about constant member functions here and correct usage of the const keyword here.
// **const object can call only const member function()**
// **Modified Code**
#include <bits/stdc++.h>
using namespace std;
class A {
public:
void hi() const {
std::cout << "hi." << std::endl;
}
};
class B {
public:
void receive(const A& a) {
a.hi();
}
};
class C {
public:
void receive(const A& a) {
B b;
b.receive(a);
}
};
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
A a;
C c;
c.receive(a);
return 0;
}
As already mentioned, one option is to make hi method const-qualified.
Another option is to use const_cast at the time of calling the hi method like so
A& ref = const_cast <A&>(a);
ref.hi();
I have implemented a simple program in C++17, in which I try to call the base class operator= from a derived class using parameter expansion. But the program does not compile.
#include "pch.h"
#include <iostream>
class D
{
public:
D()
{
std::cout << "D ctror" << std::endl;
}
D & operator = (const D & other)
{
return *this;
}
};
class C
{
public:
C()
{
std::cout << "C ctror" << std::endl;
}
C & operator = (const C & other)
{
return *this;
}
};
class B
{
public:
B()
{
std::cout << "B ctror" << std::endl;
}
B & operator = (const B & other)
{
std::cout << "operator B" << std::endl;
return *this;
}
};
template<typename... Ts> class A: public Ts...
{
public:
A(): Ts()...
{
}
A & operator = (const A & other)
{
Ts::operator =(other);
return *this;
}
};
int main()
{
A<B,C,D> a1;
A<B,C,D> a2;
a1 = a2;
}
The toolset that is used is the Visual Studio 2017 (v141)
The error that is generated is the following
error C3520: '=': parameter pack must be expanded in this context
note: while compiling class template member function 'A
&A::operator =(const A &)' note: see reference to
function template instantiation 'A &A::operator =(const
A &)' being compiled note: see reference to class template
instantiation 'A' being compiled
You need to expand the parameter pack. How about a nice fold expression:
(Ts::operator=(other), ...);
This will expand Ts... and effectively create multiple calls to operator=, one for each type in the pack.
Suppose I have the following setup:
#include <iostream>
#include <map>
using namespace std;
class A
{
public:
A() { val1 = 1;}
~A() { }
private:
int val1;
};
class B
{
public:
B() { val2 = 1;}
~B() { }
int getVal() {return val2;}
private:
int val2;
};
class C : public A, public B
{
int val3;
};
void fun(std::pair<int, B>& p) {
cout << "B val: " << p.second.getVal() << endl;
}
void fun2(B& b) {
cout << "B val: " << b.getVal() << endl;
}
int main(int argc, const char *argv[])
{
map<int, C> m;
m.insert(make_pair(1, C()));
m.insert(make_pair(2, C()));
//fun(*(m.begin())); // <---- Compilation error
fun2(m.at(1)); // Works correctly
return 0;
}
Code compiles successfully and works as expected when I make the call to fun2. However if I uncomment the line fun(*(m.begin()) I get the following compilation error:
a.cpp: In function ‘int main(int, const char**)’:
a.cpp:48:18: error: invalid initialization of reference of type ‘std::pair<int, B>&’ from expression of type ‘std::pair<const int, C>’
fun(*(m.begin()));
^
a.cpp:33:6: error: in passing argument 1 of ‘void fun(std::pair<int, B>&)’
void fun(std::pair<int, B>& p) {
Is there any way to make the compiler handle the second element of std::pair polymorphically?
P.S. Sorry if the title is misleading in any way. Couldn't find a better way of expressing this.
This:
*(m.begin())
evaluates to a nameless temporary object. To bind this to a reference, the reference must be const, so:
void fun(const std::pair<int, B>& p) {
and for that function to call getVal(), that must be const too:
int getVal() const {return val2;}
error: passing 'const A' as 'this' argument of 'void A::hi()' discards
qualifiers [-fpermissive]
I don't understand why I'm getting this error, I'm not returning anything just passing the reference of the object and that is it.
#include <iostream>
class A
{
public:
void hi()
{
std::cout << "hi." << std::endl;
}
};
class B
{
public:
void receive(const A& a) {
a.hi();
}
};
class C
{
public:
void receive(const A& a) {
B b;
b.receive(a);
}
};
int main(int argc, char ** argv)
{
A a;
C c;
c.receive(a);
return 0;
}
#edit
I fixed it using const correctness but now I'm trying to call methods inside of the same method and I get the same error, but the weird thing is that I'm not passing the reference to this method.
#include <iostream>
class A
{
public:
void sayhi() const
{
hello();
world();
}
void hello()
{
std::cout << "world" << std::endl;
}
void world()
{
std::cout << "world" << std::endl;
}
};
class B
{
public:
void receive(const A& a) {
a.sayhi();
}
};
class C
{
public:
void receive(const A& a) {
B b;
b.receive(a);
}
};
int main(int argc, char ** argv)
{
A a;
C c;
c.receive(a);
return 0;
}
error: passing 'const A' as 'this' argument of 'void A::hello()'
discards qualifiers [-fpermissive]
error: passing 'const A' as 'this' argument of 'void A::world()'
discards qualifiers [-fpermissive]
Your hi method is not declared as const inside your A class. Hence, the compiler cannot guarantee that calling a.hi() will not change your constant reference to a, thus it raises an error.
You can read more about constant member functions here and correct usage of the const keyword here.
// **const object can call only const member function()**
// **Modified Code**
#include <bits/stdc++.h>
using namespace std;
class A {
public:
void hi() const {
std::cout << "hi." << std::endl;
}
};
class B {
public:
void receive(const A& a) {
a.hi();
}
};
class C {
public:
void receive(const A& a) {
B b;
b.receive(a);
}
};
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
A a;
C c;
c.receive(a);
return 0;
}
As already mentioned, one option is to make hi method const-qualified.
Another option is to use const_cast at the time of calling the hi method like so
A& ref = const_cast <A&>(a);
ref.hi();
I have a sequence of types, which I want to be freely convertible to one another. Consider the following toy example:
struct A {
int value;
A(int v) : value(v) { }
};
struct B {
int value;
B(int v) : value(v) { }
B(A a) : value(a.value) { }
operator A() const { return A(value); }
};
struct C {
int value;
C(int v) : value(v) { }
C(A a) : value(a.value) { }
C(B b) : value(b.value) { }
operator B() const { return B(value); }
operator A() const { return A(B(*this)); } // <-- ambiguous
};
int main(int argc, const char** argv) {
C c(5);
A a(3);
a = c;
}
So as you see, I'm trying to defined each subsequent type to be convertible from all previous types using cast constructors, and to be convertible to all previous types using cast operators. Alas, this does not work as intended, as the definition of C::operator A is ambiguous according to gcc 4.7:
In member function ‘C::operator A() const’:
19:40: error: call of overloaded ‘B(const C&)’ is ambiguous
19:40: note: candidates are:
9:3: note: B::B(A)
6:8: note: constexpr B::B(const B&)
6:8: note: constexpr B::B(B&&)
Changing the expression to static_cast<A>(static_cast<B>(*this)) doesn't change a thing. Removing that line altogether results in an error message in main, as no implicit conversion sequence may use more than one user-defined conversion. In my toy example, I could perform the conversion from C to A direcly, but in my real life application, doing so would cause a lot of duplicate code, so I'd really like a solution which reuses the other conversion operators.
So how can I obtain a set of three freely interconvertible types without duplicating conversion code?
I'd try this way in struct C:
operator A() const { return this->operator B(); }
Try this:
operator A() const { return A(B(value)); }
or this:
operator A() const { return A(operator B()); }