Why is this user-defined conversion not done? - c++

Consider:
template<typename T>
struct Prop
{
T value;
operator T() { return value; }
};
int main()
{
Prop<float> p1 { 5 };
Prop<std::vector<float>> p2 { { 1, 2, 3 } };
float f1 = p1; // Works fine
float f2_1_1 = p2.value[0]; // Works fine
float f2_1_2 = p2[0]; // Doesn't compile
return 0;
}
Why doesn't the line marked as such compile? Shouldn't it perform implicit conversion using the supplied conversion operator into std::vector<>, so that the [] can be found?
There are (many) other questions on this site that ask variations on this question, but I couldn't find one that I think applies here. Does it have to do with std::vector being a template?

Implicit conversions are not considered for objects of member function calls, including the subscript operator overload.
Consider the consequences if that were allowed: Every single time any undeclared member function is called like this, the compiler would have to figure out all the types that the object can be converted to (note that any other otherwise unrelated type could have a converting constructor), and check if that has declared the missing member function. Not to mention how confusing that would be for the reader of the code (the conversion might be obvious in your conversion operator case, but not in the converting constructor case, and as far as I know, they are not otherwise treated differently).
So is there a notationally convenient way to get Prop to behave the way I want
You would have to define a member function for each of the member function of vector that you want to pass pass through transparently. Here is the subscript operator as an example:
auto operator[](std::size_t pos) {
return value[pos];
}
auto operator[](std::size_t pos) const {
return value[pos];
}
The problem is of course that all wrapped member functions must be explicitly declared. Another problem is arguments whose type depend on T. For example, vector::operator[] uses vector::size_type, which might not be defined for all T that you might use (certainly not for float). Here we make a compromise and use std::size_t.
A less laborious way of creating such "transparent" wrapper is inheritance. A publicly inheriting template would automatically have all the member functions of the parent and be implicitly convertible to it and can be referred by pointers and references of parent type. However, the transparency of such approach is a bit problematic mainly because ~vector is not virtual.
Private inheritance allows same wrapping as your member approach, but with much nicer syntax:
template<typename T>
struct Prop : private T
{
using T::operator[];
using T::T;
};
Note that inheritance approach prevents you from using fundamental types as T. Also, it makes the implicit conversion impossible (even with conversion operator) , so you cannot use Prop as T in free functions that expect T.
PS. Note that your conversion operator returns a value, so the vector must be copied, which may be undesirable. Consider providing reference versions instead:
operator T&&()&& { return *this; }
operator T&()& { return *this; }
operator const T&() const& { return *this; }

the same way that any of the
p2.size();
p2.begin();
p2.push_back(24);
// etc.
don't make sense to compile
also
p2[0];
which is equivalent with
p2.operator[](0);
doesn't make sense to compile\
If you want this behavior (i.e. for Prop<T> to borrow T members) there is a C++ proposal by Bjarne to add the dot operator to the language. I would work the same way that operator -> works for smart pointers. AFAIR it had a lot of controversy and so I wouldn't hold my breath for it.
A bit of background for the operator dot proposal—Bjarne Stroustrup
Operator Dot (R3) - Bjarne Stroustrup, Gabriel Dos Rei
Smart References through Delegation: An Alternative to N4477's Operator Dot - Hubert Tong, Faisal Vali
Alternatives to operator dot - Bjarne Stroustrup

Related

Will built-in `operator->` be used if I don't overload it?

The builtin operator-> is defined as (*p).m, which is just fine for my iterator, so overloading it would just waste my time and the maintainer's eyes.
Just trying it wouldn't guarantee portability, and I haven't been able to find an answer, though I fear that it is no, because apparently nobody has even considered it before.
Update:
I made a minimal test program to actually try this:
struct S { int m;};
struct P
{ auto& operator*() const { return s;}
auto operator->() const =default;// { return &s;}
S s;
};
int main()
{ P p;
p->m;
}
g++ (Debian 8.3.0-6) compiles this only without =default;//, so seems like defaulting or omitting the overload won't be portable for years at least.
Will built-in operator-> be used if I don't overload it?
No, only certain special member functions are implicitly declared for a given class-type(and that too under certain circumstances). And operator-> is not one of them. This can be seen from special members which states:
The six special members functions described above are members implicitly declared on classes under certain circumstances:
Default ctor
Dtor
Copy ctor
Copy assignment
Move ctor
Move assignment
(emphasis mine)
Note in the above list, there is no mention of operator->. This means that if you want to use -> with an object of your class-type then you must overload it explicitly.
Now, coming to your question about the error that you're getting.
compiles this only with the commented out definition, so seems like defaulting or omitting the overload won't be portable for years at least.
You're getting the error because operator-> cannot be defaulted. This can be seen from the same special members documentation which says:
each class can select explicitly which of these members exist with their default definition or which are deleted by using the keywords default and delete, respectively.
(emphasis mine)
Note the emphasis on "these members" above. In particular, only the six special members listed above can be defaulted. And again since operator-> is not one of them, it can't be defaulted using default.
As Anoop Rana pointed out, only special member functions can be defaulted, and, as Yksisarvinen said, the builtin operator-> exists only for builtin types.
Redundancy in overloaded operators is a long acknowledged problem.
Boost::Operators provides common overloads with CRTP,
including operator-> that mimics the builtin behavior:
#include <boost/operators.hpp>
struct S { int m;};
struct P : boost::dereferenceable< P, const S*>
{ auto& operator*() const { return s;}
S s;
};
int main()
{ P p;
p->m;
}
Unfortunately spelling out the return type is required.
(It shouldn't be required IMHO.)
Alone it isn't a big step forward, but
it's bundled in commonly needed groups like input_iteratable.

Best viable overloaded function between std::reference_wrapper<const T> and T

Recently, I've decided to write a class storing a variant with reference_wrapper<const vector> and vector for having a choice either to own the value or having only a reference of it. That is, std::variant<vector<string>, reference_wrapper<const vector<string>>>.
The interesting part is what the variant stores depending on initialization.
I did a small investigation, and it turned out, that in all cases vector<string> type wins, except for the case when passing via std::cref. The same applies to functions (somewhat expected, because constructors are similar to functions in this way)
void f(vector<string>); // #1
void f(reference_wrapper<const vector<string>>); // #2
vector<string> data;
const vector<string>& get_data();
f(data); // #1
f(std::cref(data)) // #2
f(get_data()); // #1
f(std::cref(get_data())) // #2
The question is why the vector<string> has the priority here. I looked at Best viable function section here , but it didn't make much sense. It seems, that
4) or, if not that, F1 is a non-template function while F2 is a template specialization
part chooses vector<string> over reference_wrapper<vector<string>> (because reference_wrapper constructor is templated), but I'm not sure, because I can't fully understand if they are equal using the rule
1) There is at least one argument of F1 whose implicit conversion is better than the corresponding implicit conversion for that argument of F2
Can someone please describe all the implicit conversions applied in each case and show the true reason why one overload is preferred over another? To me, they are as follows:
f(data) = f(vector<string>&) -> (*exact match* implicit conversion) -> f(vector<string>)
f(data) = f(vector<string>&) -> (*conversion* implicit conversion) -> f(reference_wrapper<vector<string>>)
Did I miss something?
Another question, connected to this topic: Ranking of implicit conversion sequences section again,here leaves a question, is T(const T&) considered an Exact match (user-defined conversion of class type to the same class) or Conversion?
First, Although std::reference_wrapper is part of standard library it is treated as user-defined type.
For example an implicit conversion from std::vector & to const std::vector & is always preferred over an implicit conversion from std::vector& to std::reference_wrapper<vector>. That is because (as per standard) the former one is a standard conversion, but the later is a user-defined conversion. the first one is called standard conversion because it adds a const to your type but the second is treated as converting some type to totally different type.
check this code and see cppreference.com.
Second, I'm trying to guess some good alternative. I see you want either to store a reference to vector OR move/(copy as cheap as possible) or (you could say directly initialize) the data inside your class if it is not already stored (safely) in some variable. Maybe you could consider using move semantics. you can play with code here
using TVar = std::variant<reference_wrapper<const vector<string>>, vector<string>>;
class Config {
private:
TVar data;
public:
const vector<string>& get_data() const{
if (data.index() == 1)
return get<1>(data);
else return get<0>(data);
}
Config(const vector<string>& it):data(cref(it)){}
Config(vector<string>&& it):data(move(it)){}
};
Here we have two functions.
One that takes reference to "stored value" (more precisely lvalue). wrapping it in cref so that it causes the reference_wrapper alternative in the variant to be the best overload.
The other does the magic. it is the reference to values that are either written directly (aka pvalues) and values that use the magic std::move function (aka xvalues). if you have never seen this, please reference this respectable Q&A What is move semantics?
catch(...) :), this is it. also notice, you don't need the std::monostate as this is only needed for making the variant default constructible (with no arguments). you can make your class default constructible like this.
Config(vector<string>&& it = {}):data(move(it)){}
There is absolutely no reason to store reference_wrapper whatsoever. Just use a pointer like any sane programmer. reference_wrapper is used to properly trigger std::invoke and associated classes/functions like thread and bind.

Why are different conversion functions for int and const int allowed?

Why is the following allowed to be compiled in C++?
#include<iostream>
using namespace std;
class mytest
{
public:
operator int()
{
return 10;
}
operator const int()
{
return 5;
}
};
int main()
{
mytest mt;
//int x = mt; //ERROR ambigious
//const int x = mt; //ERROR ambigious
}
Why does it make sense to allow different versions (based on constness) of the conversion operator to be compiled when their use always results in ambiguity?
Can someone clarify what I am missing here?
For conversion they're ambiguous; but you might call them explicitly. e.g.
int x = mt.operator int();
const int x = mt.operator const int();
I believe that in the strictest sense, even if it doesn't really make much sense for const, this is legitimate.
There is a difference between a function declaration and a function type, and they do not have the same constraints.
Function declarations may not differ in only their return type or (since C++17) exception specification. However, no such thing is said about the function type (to my knowledge).
The standard [class.conv.fct] decribes conversion functions as having such-and-such form (three alternatives listed), all of which do not look like normal function declarations, in particular they very obviously have no return type.
It does state, that the function type is "function taking no parameter returning conversion-type-id", but nowhere is it mentioned that conversion function declarations have any such thing as a return type. On the contrary, the three alternative forms listed very clearly do not have a return type.
Since conversion functions don't have a return type (... in their declaration), it cannot conflict. So, I guess, in the strictest, most pedantic sense, it's even kinda "legal", whether it makes sense or not.
If you think about it, then it somehow has to be legal, too. A class may very well have more than one conversion function to different things (not just differing by const). Such code does exist, and it sometimes makes a lot of sense going that way.
You might for example have a class File that converts to either a string (the filename) or to a handle_t (the operating system handle) in case you want to use some OS-specific or exotic function that your wrapper class doesn't directly support (think writev, tee, or epoll?) It's certainly something you'd expect to work!
If, however, we treated conversion functions as "just functions", then they'd only differ in their return type, which would render the declarations illegal. So... that wouldn't work.
why does it make sense to allow different version(based on constness) of conversion operator (to be compiled) when their use always result in ambiguity;
It usually makes no sense (apart from highly artificial use cases) and a compiler could warn you about it:
prog.cc:12:25: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
operator const int()
^
I come to the conclusion, that it's not explicitly allowed to write conversation operators that only differ by constness of their return value. It is too expensive for the compilation process to explicitly disallow it.
Remember that (member) functions that only differ by their return type
class mytest
{
int f();
const int f();
};
are forbidden:
error: ‘const int mytest::f()’ cannot be overloaded
It's just that conversion operators start with operator that makes the difference.

Can any class object be passed as test expression for any test expression such as if, while like ifstream object.

In C++, can I use my objects as test expression like ifstream objects. If not, why?
e.g.
ifstream ifs ("myfile.txt");
while( ifs ){
//read and process data..
}
I have a class, which operator do I need to overload to let compiler allow my object to be passed as test expression?
e.g.
MyClass obj1;
if( obj1 ){
//do something..
}
while( obj1 ){
//do something repeatedly..
}
Both should be valid expressions.
You have to implement a bool overload in your class. Something like this:
class myClass {
public:
explicit operator bool() const { return condition; }
};
It will work both in if and while statements. However, if your compiler does not support C++11 you can't use the explicit keyword in this overload.
There are several options you have. Probably best one is to overload the operator bool(). Like so:
class A{
public:
operator bool()
{
return flag;
}
private:
bool flag;
};
EDIT: as pointed out in the comments if you use C++11 it is better to make the operator explicit by adding the explicit keyword to the front. Otherwise probably it is better to use the operator void*()
There are a number of options.
You don’t have to implement an operator bool overload in your class.
And it’s generally not the best choice.
Best: named state checking.
The best is to use a named state checking method. For example, iostreams have the fail member, so that you can write
while( !cin.fail() ) { ... }
For your own class it can look like this:
struct S
{
bool is_good() const { return ...; } // Whatever name.
};
So-so: explicit conversion to bool.
Next best is a explicit conversion operator. Having it explicit prevents if from being called inadvertently for passing one of your objects as a function argument. An explicit conversion operator is still used in a condition, so you can write e.g.
while( cin ) { ... }
which in C++11 invokes an
explicit operator bool () const { return !fail(); }
For your own class it can look like
struct S
{
explicit operator bool () const { return ...; }
};
Ungood: implicit conversion to "private" pointer type.
Third, if you're using a compiler that does not support explicit conversions, i.e. a C++03 compiler, and if for some inexplicable reason you do not want the named checking which is the best choice, then you can choose a result type that minimizes the chance of an inadvertent call.
In C++03 iostreams used an implicit conversion to void* (instead of to bool).
Some people advocate using the "safe bool idiom" where the result is a pointer to an, in C++03, type that's inaccessible to client code.
Absolutely worst: implicit conversion to bool.
The worst option of all is like
struct S
{
operator bool () { return ... }
};
With this
One cannot see from calling code what condition is being checked.
The operator can be inadvertently called for passing an S as function argument.
The conversion can not be called on a const object.
Adding a const only makes it slightly less bad.
It’s still very bad. :-)
It is operator bool() you need to overload to provide this behaviour. But please only do this if there is a sensible semantic meaning to the conversion, that is obvious and expected by all users of the class!
Your compiler will attempt to implicit cast the expression to bool, so you will need to add a typecast operator to your class, like this:
class SomeClass {
operator bool() {
return true; // a boolean expression should go here.
}
}
this will allow for your class to be casted to a boolean type and therefore let it be used in if, while etc...
It is however important to note that this allows implicit conversions from your type to bool and it is important to make sure that this makes sense.
Often it is more sensible to provide a method for the behavior, such as:
while (myObj.hasMoreElements())
or
if (someObj.isValid())
This makes it immediately clear what is being tested. However, if a conversion to bool makes sense, go for it.
You can overload any number of type conversion operators; the
traditional one was operator void*()() const, to return a null
pointer for false, and a non-null pointer (tradiionally this)
for true. In C++11, you can also overload explicit operator
bool() const, but this is not recommended if your compiler
doesn't yet allow explicit; the fact that bool is an
integral type, and that without the explicit, it will convert
to any other integral type, can lead to some surprising overload
resolutions .
If you do this, you should also overload operator!() const, so
that if ( ! myObj ) is well defined as well.
And finally, you should really reflect as to whether you want to
do this. The ostream classes get away with it because they're
part of the standard, and everyone sees, uses and knows them,
and the while ( someStream >> object ) idiom is ubiquitious.
But on the whole, it's misleading and an abuse of operator
overloading for any class which has more than two possible
states; an isValid or isReady or whatever function is more
appropriate.

overloading non-member conversion to bool operator

I am trying to write bool-conversion operator for std::bitset
I tried:
template<size_t size>
operator bool(std::bitset<size> & b)
{
return b.any();
}
but I got
error C2801: 'mynamespace::operator bool' must be a non-static member
from my visual-studio.
But when I look up C2801 explanation it says nothing about conversion operators (only about =, ->, [],())
So, is it possible to somehow write "Conversion std::bitset to bool operator?"
(I can not call b.any() in my if-statements, because the same code must run when std::bitset is replaced with unsigned or something
typedef std::bitset<x> Bitset;
//typedef unsigned Bitset;
so the ideal syntax will be like:
Bitset b = whatewer;
if(b)
doStuff();
)
If this overloading is not possible, what is the recommended workaround?
so far I use it like:
if(b == Bitset(0))
doStuff();
but I dont like it.
Thank you
As the error message says, the conversion operator must be a non-static member of a class. That is true.
I can not call b.any() in my if-statements, because the same code must run when std::bitset is replaced with unsigned or something.
If that is your problem, then you can use function overload, and call it passing the argument which will return a boolean value:
template<typename T>
bool to_bool(T const & b)
{
return b; //implicit conversion (if allowed) for all other types
}
template<size_t N>
bool to_bool(std::bitset<N> const & b)
{
return b.any();
}
then use it as:
if (to_bool(whatever))
{
}
It will call the correct overload. If the type of whatever is std::bitset<N> then the second overloaded function will be called, or else the first one will be called.
§12.3.2/1: "A member function of a class X with a name of the form [...] specifies a conversion from X to the type specified..." (C++11 uses the same section number and nearly the same wording, adding only that the function takes no parameters).
The other possible way to define a conversion is a constructor (§12.3.1), which is obviously a class member as well.
In short, yes, conversions must always be defined as member functions.
One way to do what you want would be to write a wrapper around std::bitset that provides the conversion you care about:
template <int size>
class mybitest {
std::bitset<size> bits;
public:
operator bool() { return bits.any(); }
}
But if you decide to do that, you'll need to write forwarding functions for essentially all the pieces of bitset you're using (ctors, assignment, etc.)
The standard is a bit unclear on this (12.3.2):
A member function of a class X having no parameters with a name of the form [...] specifies a conversion from X to the type specified by the conversion-type-id. Such functions are called conversion functions. No return type can be specified. If a conversion function is a member function, the type of the conversion function (8.3.5) is “function taking no parameter returning conversion-type-id”.
The first sentence seems to imply that only member functions can be conversion functions, but I'm not sure what the purpose of the conditional "if a conversion function is a member function" is.
I'd take the first sentence as binding and conclude that a conversion function must be a member function.
in case this helps somebody, you can actually provide a not operator instead
template<size_t size>
operator !(std::bitset<size> & b)
{
return !b.any();
}
and use it like so using the !! idiom:
if (!!whatever)
{
}
still not ideal, but a bit closer I think.