To test and display the result of some functions of my library, I am creating a set of handy functions.
I have an execute function that looks like :
template <typename R, typename I>
std::string execute( const std::string& func_name, R(*func_ptr)( const I& ), const I& func_input );
It calls the function, and display the results and arguments in a formatted string that I can send to std::cout.
The problem is that some of my functions do not return convertible-to-string results. I thought I could simply overload the global ::operator std::string with something like:
template <typename T>
operator std::string( const std::vector<T>& v );
But GCC complains:
error: 'operator std::string(const std::vector<T, std::allocator<_CharT> >&)' must be a nonstatic member function
Well, the problem of course is that I cannot add member operators to std::vector, and even for my classes, I don't want to pollute them with "for testing" conversion operators.
I guess that I can add a layer of indirection and use a function instead of a conversion operator, but that would not be the more aesthetic solution. I could also overload ::operator << for std::ostream and use a std::ostringstream, but that also is not the cleanest solution.
I wondered if the global conversion operator is really not overloadable, and if so, why.
Conversion operators (cast operators) must be a member of the convertible class that produces the converted type. As assignment operators, they must be member functions, as your compiler is telling you.
Depending on how much effort you want to put into the debug part of it, you could try to use metaprogramming to forward your execute method to different actual implementations, providing specific ones for containers that will print the contents.
Why don´t you want to provide operator<< for your types? I think that is actually the idiomatic solution. Unlike other languages that you use methods that convert to string to produce printable results, in C++ the idiomatic way is providing operator<< and then using stringstreams (or boost::lexical_cast or some similar solution) to convert to strings based on the operator<< implementation. There is a simple utility class here to create a string from elements that override operator<< if you want to use that for a start point.
I wondered if the global conversion operator is really not overloadable, and if so, why.
No, there is no such thing. Conversion functions must be a member of a class. If it weren't so, it would make overload resolution a particularly vexing problem for the compiler by introducing ambiguities.
There is no user defined global conversion operator. You must control either the target type (in which case a non explicit one parameter constructor is the conversion operator) or the source type (in which case you have to overload the member operator target()).
A conversion function must be a member function. The function may not specify a return type, and the parameter list must be empty. They should be used sparingly and there should be a clear conversion path from one type to another type. Otherwise they can lead to unexpected results and mysterious errors.
Unfortunately there is no such thing as a global casting operator. Surprisingly. But templates are your friend.
Sometimes you do not want to expose the casting to the interface put would want to keep this anonymous for a specific implementation only. I usually add a template as() method to the class which can also do type checks in the cast, etc. and lets you handle the way you want to implement the casting (e.g. dynamic, shared, ref, etc).
Something like this:
template< class EvtT >const EvtT& as() const throw( std::exception )
{
const EvtT* userData = static_cast<const EvtT*>( m_UserData );
ASSERT( userData, "Fatal error! No platform specific user data in input event!" );
return *userData;
}
m_UserData is an anonymous type which only the implementation knows. While this is strictly a non-typed cast (I do not use type cecks here) this could be replaced by a dynamic_cast and proper casting exceptions.
The implementation simply does this:
unsigned char GetRawKey( const InputEvent& ie )
{
const UserEvent& ue = ie.as<const UserEvent>();
...
Related
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.
This question is easiest to illustrate with an example, so here goes:
Is code like the following guaranteed to be valid, and compile & run correctly?
(Not all implementations actually compile it correctly, but I'm wondering if that's a bug.)
#include <algorithm>
class Picky
{
friend
Picky *std::copy<Picky const *, Picky *>(Picky const *, Picky const *, Picky *);
Picky &operator =(Picky const &) { return *this; }
public:
Picky() { }
};
int main()
{
Picky const a;
Picky b;
std::copy<Picky const *, Picky *>(&a, &a + 1, &b);
return 0;
}
std::copy requires an output iterator ([algorithms.general]/p5); output iterators, among other things, require *r = o to be valid ([output.iterators], Table 108) - not just "valid sometimes" or "valid in some contexts".
Since for Picky *p, a;, *p = a isn't valid in most contexts, Picky * isn't a valid output iterator.
Hmm it'd be great if you could generalize your answer to other things
beyond the particular example I gave. Like, for example,
std::vector::push_back(T const &), or whatever.
Befriending a member function is an absolute no-no, because you aren't even guaranteed that there's a member function with that signature ([member.functions]/p2, which Stephan T. Lavavej calls the "STL Implementers Can Be Sneaky Rule"):
An implementation may declare additional non-virtual member function
signatures within a class:
by adding arguments with default values to a member function signature187 [Note: An implementation
may not add arguments with default values to virtual, global, or non-member functions. — end note];
by replacing a member function signature with default values by two or more member function signatures with equivalent behavior; and
by adding a member function signature for a member function name.
187 Hence, the address of a member function of a class in the C++ standard library has an unspecified type.
The code might compile if std::copy() does not call any other non-friend functions but I've yet to encounter any such implementation. And there is no requirement in the standard limiting HOW std::copy() achieves the required effect.
However, it does require a working and accessible assignment 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.
This is annoying, i can write a function with these parameters/return, but why cant i define an operator to do this?
-edit- i am actually trying to overload << the below is just for reference.
From msdn
// C2803.cpp
// compile with: /c
class A{};
bool operator< (const A *left, const A *right); // C2803
// try the following line instead
// bool operator< (const A& left, const A& right);
gcc error
error: ‘bool operator<(const A*, const A*)’ must have an argument of class or enumerated type
Because every user-defined operator overload needs at least one user-defined type as a parameter. A point isn't a user-defined type.
C++03 standard, §13.5 [over.oper] p6:
An operator function shall either be a non-static member function or be a non-member function and have at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an enumeration.
Because you aren't allowed to cheat.
If you could override comparison operators for pointer types, then you would no longer be able to compare those pointers by value (aka: by the actual numerical pointer values). And that's kind of important and occasionally useful.
My real code is actually <<. Why cant i use it for that?
For the same reason: pointers are C++-basic types. They aren't user-defined types. Do you want to be able to not left-shift pointer values anymore? OK, obviously you do, but C++ won't let you.
You can only override operators when C++ does not have existing functionality for operators with those types (with a few exceptions). C++ already has operator< and operator<< for pointers, so you're not allowed to change what they do.
To test and display the result of some functions of my library, I am creating a set of handy functions.
I have an execute function that looks like :
template <typename R, typename I>
std::string execute( const std::string& func_name, R(*func_ptr)( const I& ), const I& func_input );
It calls the function, and display the results and arguments in a formatted string that I can send to std::cout.
The problem is that some of my functions do not return convertible-to-string results. I thought I could simply overload the global ::operator std::string with something like:
template <typename T>
operator std::string( const std::vector<T>& v );
But GCC complains:
error: 'operator std::string(const std::vector<T, std::allocator<_CharT> >&)' must be a nonstatic member function
Well, the problem of course is that I cannot add member operators to std::vector, and even for my classes, I don't want to pollute them with "for testing" conversion operators.
I guess that I can add a layer of indirection and use a function instead of a conversion operator, but that would not be the more aesthetic solution. I could also overload ::operator << for std::ostream and use a std::ostringstream, but that also is not the cleanest solution.
I wondered if the global conversion operator is really not overloadable, and if so, why.
Conversion operators (cast operators) must be a member of the convertible class that produces the converted type. As assignment operators, they must be member functions, as your compiler is telling you.
Depending on how much effort you want to put into the debug part of it, you could try to use metaprogramming to forward your execute method to different actual implementations, providing specific ones for containers that will print the contents.
Why don´t you want to provide operator<< for your types? I think that is actually the idiomatic solution. Unlike other languages that you use methods that convert to string to produce printable results, in C++ the idiomatic way is providing operator<< and then using stringstreams (or boost::lexical_cast or some similar solution) to convert to strings based on the operator<< implementation. There is a simple utility class here to create a string from elements that override operator<< if you want to use that for a start point.
I wondered if the global conversion operator is really not overloadable, and if so, why.
No, there is no such thing. Conversion functions must be a member of a class. If it weren't so, it would make overload resolution a particularly vexing problem for the compiler by introducing ambiguities.
There is no user defined global conversion operator. You must control either the target type (in which case a non explicit one parameter constructor is the conversion operator) or the source type (in which case you have to overload the member operator target()).
A conversion function must be a member function. The function may not specify a return type, and the parameter list must be empty. They should be used sparingly and there should be a clear conversion path from one type to another type. Otherwise they can lead to unexpected results and mysterious errors.
Unfortunately there is no such thing as a global casting operator. Surprisingly. But templates are your friend.
Sometimes you do not want to expose the casting to the interface put would want to keep this anonymous for a specific implementation only. I usually add a template as() method to the class which can also do type checks in the cast, etc. and lets you handle the way you want to implement the casting (e.g. dynamic, shared, ref, etc).
Something like this:
template< class EvtT >const EvtT& as() const throw( std::exception )
{
const EvtT* userData = static_cast<const EvtT*>( m_UserData );
ASSERT( userData, "Fatal error! No platform specific user data in input event!" );
return *userData;
}
m_UserData is an anonymous type which only the implementation knows. While this is strictly a non-typed cast (I do not use type cecks here) this could be replaced by a dynamic_cast and proper casting exceptions.
The implementation simply does this:
unsigned char GetRawKey( const InputEvent& ie )
{
const UserEvent& ue = ie.as<const UserEvent>();
...