Compiler error trying to call converting constructor - c++

The following code doesn't work. I don't know why. Does that has anything to do with implicit/explicit? Is that called a conversion?
#include <type_traits>
template<typename T>
class A {
public:
A(T x) {_x=x;}
template<typename T2> explicit A(const A<T2> &r) {}
template<typename T2> explicit A(A<T2> &r){}
template<typename T2>
void operator=(const A<T2>& rhs) { _x = rhs._x; }
template<typename T2>
void operator=(A<T2>& rhs) { _x = rhs._x; }
T _x;
};
int main() {
const A<int> a(10);
A<int> b = a;
b = A<int>(5);
A<int> c(a);
b(a); // not working. why?
}
Error: g++ 6
test.cpp: In function β€˜int main()’:
test.cpp:25:12: error: no match for call to β€˜(A<int>) (const A<int>&)’
b(a); // not working. why?

I'm not sure what you expect b(a); to do but it is not going to do what you want. An object can only be constructed once. After it has been constructed you cannot reconstruct it. What you have when you do b(a); is you try to call the operator() of the class. Since you do not have one you get a compiler error. If you want to set b to the value of a then you need
b = a;

Related

Why does a generic type that can be casted not get implicitly converted?

I have a class A and a class B, both generic with a type parameter T. An object of A<T> can be casted to B<T>. I have a generic operator overload on B that I want to be able to call on an A object and a B object, where the A object gets implicitly converted.
When I try this it does not compile:
template <typename T>
class A {};
template <typename T>
class B {
public:
B() {}
B(const A<T> &a) {}
};
template <typename T>
B<T> operator*(const B<T> &obj1, const B<T> &obj2) {
return B<T>(); // doesn't matter
}
int main() {
A<int> objA;
B<int> objB;
B<int> combined1 = objA * objB; // error: operator* isn't defined on these types
B<int> combined2 = static_cast<B<int>>(objA) * objB; // fine
return 0;
}
However when A and B aren't generic, it works fine:
class A {};
class B {
public:
B() {}
B(const A &a) {}
};
B operator*(const B &obj1, const B &obj2) {
return B(); // doesn't matter
}
int main() {
A objA;
B objB;
B combined1 = objA * objB; // fine
B combined2 = static_cast<B>(objA) * objB; // also fine
return 0;
}
Why is this? Is there something about making the operator overload generic that means the type can't be inferred?
In general, implicit conversions are not allowed while doing argument deduction, I can think of a derived to base as one that is allowed. The expression
B<int> combined1 = objA * objB;
expect to find viable overloads for objA * objB, including those found by ADL, one possible is:
template <typename T>
B<T> operator*(const A<T> &obj1, const B<T> &obj2) {...}
but none is found, the overload you provide is not a candidate, hence the call fail, but if you provide the explicit template argument to the operator, then there will be nothing to deduce and the implicit conversion through the converting constructor will allow the call:
B<int> combined1 = operator*<int>(objA, objB);
But I would not do that, stick with the cast it better explain the intent.
You can define friend function in class A which call your template function
template <class T>
class B;
template <typename T>
class A {
friend B<T> operator*(const B<T> &obj1, const B<T> &obj2) {} # here call template function
};
template <typename T>
class B {
public:
B() {}
B(const A<T> &a) {}
};
template <typename T>
B<T> operator*(const B<T> &obj1, const B<T> &obj2) {
return B<T>(); // doesn't matter
}
int main() {
A<int> objA;
B<int> objB;
B<int> combined1 = objA * objB; // fine
B<int> combined2 = static_cast<B<int>>(objA) * objB; // fine
return 0;
}
During argument deduction, conversion/promotion doesn't occurs, so for
objA * objB
When checking validity of candidates overload, T cannot be deduced for:
template <typename T> B<T> operator*(const B<T> &, const B<T> &);
So that overload is rejected.
One way to fix that is to create a non template function. Asit should apply to classe template, one way to do it is with friend functions:
template <typename T>
class B {
public:
B() {}
B(const A<T>&) {}
friend B operator*(const B&, const B&) { return /*...*/; }
};
Now, objA * objB considers overload B<int> operator*(const B<int>&, const B<int>&) and conversion can occurs to see if function is viable (and it is).
Demo

Inherit operators defined outside class

In this minimal example I have a class A with an operator + defined outsise of it:
template<class T> class A {};
template<class T1, class T2> void operator+(A<T1> a, A<T2> b) {}
template<class T> class B : public A<T> {};
int main(int, char**) {
B<int> a, b;
a + b;
return 0;
}
I've tried to create an implicit conversion from B to A but it requires the operator+ to be a friend of A and be defined inside A which will cause problems when more than one instance of A<...> gets instantiated.
So, is there any other way to do this without having to define the operator+ again?
Thank you in advance for any help.
template<class T> class A {
template<class T2>
friend void operator+(A const& lhs, A<T2> const& rhs) {}
};
template<class T> class B : public A<T> {};
int main(int, char**) {
B<int> a, b;
a + b;
return 0;
}
this works. The assymetry in + (one template, one not) ensure that multiple As don't conflict with their +.
In some situations you really need lhs to be an instance of B:
template<class T> struct A {
template<class D, class T2, std::enable_if_t<std::is_base_of<A, D>{}, bool> =true >
friend void operator+(D const& lhs, A<T2> const& rhs) {
std::cout << D::name() << "\n";
}
static std::string name() { return "A"; }
};
template<class T> struct B : public A<T> {
static std::string name() { return "B"; }
};
int main(int, char**) {
B<int> a, b;
a + b;
return 0;
}
which uses A's operator+, but the LHS is of type B. Doing this for B<T2> on the right hand side isn't very viable, it gets ridiculous.

C++ templated class self-inheritance

I've got this code:
template<typename A, typename B = A>
class MyClass;
template<typename A>
class MyClass<A, void>
{
protected:
A a;
MyClass<A, void>(const A& a):
a(a)
{}
public:
const A& getA() const
{
return a;
}
};
template<typename A, typename B>
class MyClass : public MyClass<A, void>
{
private:
B b;
public:
MyClass<A, B>(const A& a, const B& b):
MyClass<A, void>(a), b(b)
{}
const B& getB() const
{
return b;
}
const auto getAplusB() const
{
return a+b;
}
};
getAplusB method fails to compile with message a is not declared. However, inheritance seems to work, so I can use this->getA() + b. I've also tried to do dynamic_cast<const MyClass<A, void>*>(this)->a + b, but got another compilation error a is protected. What am I missing here?
You will need to simply use this->a or a qualified name MyClass<A, void>::a. This is because a is member of a base class-template. There is such a thing known as name lookup - When the compiler sees a name, it does the said name lookup.
Simply trying to make unqualified accesses a will not work because it's a dependent name (by meaning of it depending on the instantiation of some template somewhere). Hence you have to qualify the accesses to a

C++ noexcept unknown member function

#include<iostream>
#include<utility>
using namespace std;
struct A
{
void set(const int &){}
void set(int &&) noexcept
{}
};
template<class Assign,class T,class Func>
struct B
{
B& operator=(const Assign &)
{
return *this;
}
B& operator=(Assign &&) noexcept(noexcept(declval<T>().set(declval<Assign>())))
{
return *this;
}
};
int main()
{
cout<<is_nothrow_assignable<B<int,A,void(A::*)(int &&)>&,int&&>::value<<endl;
}
I want to make the line
B& operator=(Assign &&) noexcept(noexcept(declval<T>().set(declval<Assign>())))
to
B& operator=(Assign &&) noexcept(noexcept(declval<T>().Func(declval<Assign>())))
(But it occurs compilation error.)
So that user can specify which member function should be used.
Is there any possible to do that without knowing which member function should be called in advance?
If you use another parameter to specify the function, it'll work.
template<class Assign,class T,class Func, Func f> struct B
//...
B& operator=(Assign &&) noexcept(noexcept((declval<T>().*f)(declval<Assign>())))
//...
cout<<is_nothrow_assignable<B<int,A,void(A::*)(int &&), &A::set>&,int&&>::value<<endl;
Add a Func non-type parameter to B, use member function pointer call syntax in the noexcept operator, and then you can specify the function by passing a pointer to it.
Full code here, if it needs more context.

Is it okay to remove const qualifier when the call is from the same non-const version overloaded member function?

For example:
struct B{};
struct A {
const B& findB() const { /* some non trivial code */ }
// B& findB() { /* the same non trivial code */ }
B& findB() {
const A& a = *this;
const B& b = a.findB();
return const_cast<B&>(b);
}
};
The thing is I want to avoid repeating the same logic inside the constant findB and non-constant findB member function.
Yes, you can cast the object to const, call the const version, then cast the result to non-const:
return const_cast<B&>(static_cast<const A*>(this)->findB());
Casting away const is safe only when the object in question was not originally declared const. Since you are in a non-const member function, you can know this to be the case, but it depends on the implementation. Consider:
class A {
public:
A(int value) : value(value) {}
// Safe: const int -> const int&
const int& get() const {
return value;
}
// Clearly unsafe: const int -> int&
int& get() {
return const_cast<int&>(static_cast<const A*>(this)->get());
}
private:
const int value;
};
Generally speaking, my member functions are short, so the repetition is tolerable. You can sometimes factor the implementation into a private template member function and call that from both versions.
I think, that using cast here is ok, but if you definitely want to avoid it, you can use some template magic:
struct B
{
B(const B&)
{
std::cout << "oops I copied";
}
B(){}
};
struct A {
public:
A(){}
A(const A&){ std::cout << "a is copied:(\n";}
const B& findB() const { return getter(*this); }
B& findB() { return getter(*this); }
private:
template <typename T, typename V>
struct same_const
{
typedef V& type;
};
template <typename T, typename V>
struct same_const<const T, V>
{
typedef const V& type;
};
template <typename T>
static typename same_const<T,B>::type getter(T& t) { return t.b;}
B b;
};
int main()
{
A a;
const A a_const;
const B& b1 = a.findB();
B& b2 = a.findB();
const B& b3 = a_const.findB();
//B& b4 = a_const.findB();
}