Template accessor can not convert from T to T& (C++) - c++

I have a templated class:
template<class T>
class MyClass
{
public:
MyClass(T mem)
{
member = mem;
}
T& GetMember() const
{
return(member);
}
T member;
};
and then I do this:
MyClass<bool> test(true);
bool someBool = test.GetMember();
And I get a compile error saying it can't convert 'bool' to 'bool&'
How can I fix this?

The problem is you have a const member function, but you are returning a mutable reference from it. (btw cl's error message is error C2440: 'return' : cannot convert from 'const bool' to 'bool &' which makes that clear). That is probably is not your real intent, so either use
T GetMember() const
{
return member;
}
or
const T& GetMember() const
{
return member;
}

T& GetMember() const
should be
const T& GetMember() const
const is not just a keyword to make your code look safer, it acutally enforces your code to be safer ;)

Related

template specialization based on const-qualified instantiation

Suppose I have a templated class:
template<typename T>
class A
{
public:
A(T& val) : m_val{val} {}
T& val() { return m_val; }
const T& val() const { return m_val; }
//etc...
private:
T& m_val;
};
Can I have template specialization which is different for lines (1) and (2):
int a = 5;
A<int> x {a}; //(1)
const A<int> y {a}; //(2)
const int b = 10;
const A<int> z {b}; //error: binding reference of type ‘int&’ to ‘const int’ discards qualifiers
Basically, in the const case I want to declare the underlying m_val as const T& m_val; because I've instantiated my wrapper class as const and I want to signify that the internal reference should also be const in this case.
Is this possible? I've tried several solutions and the only one that seem to work is to explicitly add const to the template argument like this: const A<const int> z {b};
Is it possible to avoid this inner const-qualifier?
EDIT: Changed the member variable to be a reference to show how const-ness can cause trouble for the compiler in this situation.
EDIT2: Removed the default constructor to simplify the problem.

How to resolve an apply_visitor within another static_visitor in boost::variant? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I get a compiler regarding apply_visitor within the current operator.
I tested all the apply_visitor outside of that method and it works perfectly fine. Just when trying to use it within that method it runs into a bunch of issues.
The error message is confusing me.
So, Why is trying to use apply_visitor for a different visitor is running into problems within the current visitor?
Here the Snippet of the code that have give me the errors:
typedef boost::make_recursive_variant<string, int, vector<boost::recursive_variant_ > >::type ObjectE;
class ReturnType : public boost::static_visitor<string> {
public:
string operator()(string &s) { return "string"; }
string operator()(int i) {return "int";}
string operator()(std::vector<ObjectE> const &v) {return "vector";}
};
class ReturnVal : public boost::static_visitor<string> {
public:
string operator()(string &s) { return s; }
string operator()(int i) {return to_string(i);}
string operator()(std::vector<ObjectE> const &v) {return "vector";}
};
class ReturnV : public boost::static_visitor<vector<ObjectE>> {
public:
vector<ObjectE> operator()(string &s){ return {};}
vector<ObjectE> operator()(int i) {return {};}
vector<ObjectE> operator()(vector<ObjectE> const &v) {return v;}
};
struct create_Str {
using result_type = void;
std::ostream & out;
template <typename T> void call(T const &v) { return operator()(v);}
template <typename... Ts> void operator()(boost::variant<Ts...> const &v) {
return boost::apply_visitor(*this, v);
}
void operator()(int i) { out << i; }
void operator()(std::string const &s) { out << s; }
template <typename... Ts> void operator()(std::vector<Ts...> const &v) {
string name = boost::apply_visitor(ReturnVal(), v[0]);
if (v.size() == 3 && isOp(name)) {
}
else if (v.size() == 3 && isListCons(name)) {
call(v[1]);
ObjectE tail = v[2];
for (;;) {
if ("[]" == boost::get<string>(tail) || "nil" == boost::get<string>(tail)) {
break;
}
if ( !(boost::apply_visitor(ReturnType(), tail) == "vector")) {
}
vector<ObjectE> list = boost::apply_visitor(ReturnV(), v[2]);;
if (!(list.size() == 3 && isListCons(boost::apply_visitor(ReturnVal(), list[0])))) {
}
}
}
}
};
At first, I thought maybe
vector<ObjectE> list = v[2];
was the issue. So I created a visitor who will return a vector.
However, it seem that most of the errors are :
error: no match for call to '(const ReturnVal) (std::__cxx11::basic_string<char>&)'
which I'm not sure what it mean.
Can someone explain to me what the issue is?
Hah. Look back at my older answer to you:
Calls like
boost::apply_visitor(ReturnType(), tail)
call pass the visitor as a temporary, so it can only bind to a const&. This means that all call-operator overloads required must be const-qualified, because otherwise they won't apply, as you're being told:
Live On Coliru
#include <boost/variant.hpp>
struct Ok : boost::static_visitor<> {
void operator()(std::string const&) const {}
void operator()(int) const {}
};
struct NotWorkingWithTemporaries : boost::static_visitor<> {
void operator()(std::string const&) const {}
void operator()(int) {} // whoops, missing const-qualifier
};
int main() {
boost::variant<std::string, int> v;
boost::apply_visitor(Ok{}, v);
//boost::apply_visitor(NotWorkingWithTemporaries{}, v); // COMPILE ERROR
// however, this works:
NotWorkingWithTemporaries not_a_temporary;
boost::apply_visitor(not_a_temporary, v);
}
Compiles. Ucommenting the line commented with // COMPILE RROR gives:
Live On Coliru
In file included from /usr/local/include/boost/variant.hpp:17:0,
from main.cpp:1:
/usr/local/include/boost/variant/variant.hpp: In instantiation of 'boo...
/usr/local/include/boost/variant/detail/visitation_impl.hpp:114:9: r...
/usr/local/include/boost/variant/detail/visitation_impl.hpp:154:41: ...
/usr/local/include/boost/variant/detail/visitation_impl.hpp:238:5: r...
/usr/local/include/boost/variant/variant.hpp:2390:48: required from ...
/usr/local/include/boost/variant/variant.hpp:2404:43: required from ...
/usr/local/include/boost/variant/variant.hpp:2429:52: required from ...
/usr/local/include/boost/variant/detail/apply_visitor_unary.hpp:84:43:...
main.cpp:17:56: required from here
/usr/local/include/boost/variant/variant.hpp:1046:24: error: no match ...
return visitor_(operand);
~~~~~~~~^~~~~~~~~
main.cpp:9:10: note: candidate: void NotWorkingWithTemporaries::operat...
void operator()(std::string const&) const {}
^~~~~~~~
main.cpp:9:10: note: no known conversion for argument 1 from 'int' t...
main.cpp:10:10: note: candidate: void NotWorkingWithTemporaries::opera...
void operator()(int) {} // whoops, missing const-qualifier
^~~~~~~~
main.cpp:10:10: note: passing 'const NotWorkingWithTemporaries*' as ...
In file included from /usr/local/include/boost/variant.hpp:17:0,
from main.cpp:1:
/usr/local/include/boost/variant/variant.hpp:1046:32: error: return-st...
return visitor_(operand);
Skip the required from chain, scan for error: first and then notice the note: that says:
main.cpp:10:10: note: candidate: void NotWorkingWithTemporaries::operator()(int) <near match>
void operator()(int) {} // whoops, missing const-qualifier
^~~~~~~~
main.cpp:10:10: note: passing 'const NotWorkingWithTemporaries*' as 'this' argument discards qualifiers
It's pretty clear once you look for it: passing 'const NotWorkingWithTemporaries*' as 'this' argument discards qualifiers. The only thing you need to know is const is known as a qualifier¹.
¹ const, volatile and rvalue-ref (&&)
OTHER REMARKS
Trying to get the rest of your non-self-contained question code to compile reveals similar issues with the std::string overloads:
std::string operator()(std::string const & /*s*/) const { return "std::string"; }
(note std::string const& instead of std::string&).
Other than that... it look as though you're abusing vectors to represent Expressions. Why not make it strong typed and a lot less error-prone?
See e.g. Building a Custom Expression Tree in Spirit:Qi (Without Utree or Boost::Variant)

passing const this to function accepting const pointer is not const-correct?

I have a class template Foo with the following member function:
bool contains(const T& item) const
I have instantiated this with a pointer type: Foo<Bar*>, leading me to expect that the member function will now have the following signature:
bool contains(const Bar*& item) const
In a const Bar member function, I attempt to pass this to Foo<Bar*>::contains:
bool Bar::func(const Foo<Bar*>& foo) const
{
return foo.contains(this);
}
This fails to compile, with the following error:
error: invalid conversion from ‘const Bar*’ to ‘Bar*’
Question:
Why is my const T& parameter not const-correct?
What signature for Foo<T>::contains(...) const is required to allow calling with this to compile?
Full example:
#include <vector>
#include <algorithm>
template<typename T>
struct Foo
{
bool contains(const T& item) const
{
return false;
}
};
struct Bar
{
bool func(const Foo<Bar*>& foo) const
{
return foo.contains(this);
}
};
Error output:
scratch/main.cpp:17:33: error: invalid conversion from ‘const Bar*’ to ‘Bar*’ [-fpermissive]
return foo.contains(this);
^
scratch/main.cpp:7:10: note: initializing argument 1 of ‘bool Foo<T>::contains(const T&) const [with T = Bar*]’
bool contains(const T& item) const
I have instantiated this with a pointer type: Foo<Bar*>, leading me
to expect that the member function will now have the following
signature:
bool contains(const Bar*& item) const
That's where the problem is. When T = Bar*, the expression
bool contains(const T& item) const
Will actually compile to
bool contains(Bar * const & item) const
That is, a reference-to-a-const-pointer-to-Bar.
It makes sense of you think about it: you want T to be const, and then you want a reference to that.
If you want to apply the const in the usual "intended" way (though this might cause some surprises for seasoned C++ programmers), you can declare your container and member function in the following way:
template <class T>
class Container {
public:
using const_bare_type = typename std::conditional<
std::is_pointer<T>::value,
typename std::remove_pointer<T>::type const*,
const T>::type;
bool contains(const const_bare_type& item);
};
Compiler alerts about wrong line, you must write:
bool func(const Foo<const Bar*>& foo) const
I.e. const Bar* in template parameter, because Bar::func receives const Bar * this as its parameter, and cannot convert it to Bar* in template parameter (cannot remove const).

how would you specialize std::greater

have a
std::list<MyBaseClass*> objects;
how ( mean a syntax) would you specialize std::greater
for the sort method of std::list
template<> class std::greater<MyBaseClass*> {
public:
bool operator()(const MyBaseClass*& lhs, const MyBaseClass*& rhs) const
{
return lhs->get_index() > rhs->get_index();
}
produces the error:
C2662: 'int MyBaseClass::get_index(void)' : cannot convert 'this' pointer from 'const MyBaseClass' to 'MyBaseClass &'
Conversion loses qualifiers
can you explain me the problem please?
Your implementation of eidos::MyBaseClass::get_index() needs to be marked as "const".

template function and boost::remove_reference

I'm tracking down a C++ compiler error which I can't figure out. I've reduced it to this code:
#include <boost/config.hpp>
#include <boost/type_traits/remove_reference.hpp>
template<typename T> inline const T bar( T in )
{
typedef BOOST_DEDUCED_TYPENAME boost::remove_reference<T>::type nonref;
const nonref* inPtr = &in;
return *inPtr;
}
class Foo
{
};
int main()
{
Foo foo;
const Foo& ref = bar< Foo& >( foo );
}
which results in:
tt.cpp: In function ‘const T bar(T) [with T = Foo&]’:
tt.cpp:19:39: instantiated from here
tt.cpp:9:13: error: invalid initialization of reference of type ‘Foo&’ from expression of type ‘const nonref {aka const Foo}’
What's the actual issue here? Why is the const missing in the return value? I need the remove_reference since the actual code requires it.
Applying const to a reference type does nothing. You need to make the template argument const foo &, or else remove the reference and then add back both const and the reference in the function signature itself.
See also When should I use remove_reference and add_reference? particularly the second paragraph.
Using VisualStudio 2008 I get the following error
error C2440: 'return' : cannot convert from 'const nonref' to 'Foo &'
Changing bat to
template<typename T> inline const typename boost::remove_reference<T>::type& bar( T in )
{
typedef BOOST_DEDUCED_TYPENAME boost::remove_reference<T>::type nonref;
const nonref* inPtr = &in;
return *inPtr;
}
fixes this and the code compiles.
Returning const T from your function doesn't do what you are expecting. From your code I understand that you expect it to return const Foo&, which is a reference to an immutable object of type Foo.
But when T is Foo&, the expression const T means an immutable reference to an object of type Foo. Since the references are always immutable, the const part is just dropped (according to the paragraph 8.3.2 of the spec)! That is, your function returns Foo& and not const Foo& and that's what the compiler tries to tell you.