C++ builder pattern insert operator `<<` style - c++

I have a log builder type like so:
Log Log::log(const int logLevel)
{
return Log(logLevel);
}
Log& operator <<(Log& log, const char * s)
{
if (log.hasLogLevel())
log.out << s;
return log;
}
I'm using the above code like this:
Log::log(1) << "Hello logger";
But I'm getting these warnings and it wasn't until recently I realized that it's because the way the operator is overloaded (or at least this is what I'm thinking)
warning C4239: nonstandard extension used : 'argument' : conversion from 'snow::Log' to 'snow::Log &'
I thought this would be fine because it's the same rvalue? that's being passed/chained through these operator overloads. I don't think this code compiles outside of MSVC++ and I would like to know what I should be doing differently here.
If the solution is to simply use rvalue references then I'm cool with that but I'd like to understand a little better what's going on here.

The problem is that the Log is an rvalue, and that is not allowed to bind to the non-const reference parameter. Microsoft doesn't enforce this, bacuase they have some legacy code that would break.
If you only want to output strings, one workaround is to make the operator<< a member of the Log class. You are allowed to call members of an rvalue.
If you want to use other non-member operators, you can provide an rvalue to lvalue converter, like the standard streams do in C++11.
Something like
template<class T>
Log& operator<<(Log&& log, const T& value)
{ return log << value; }
using the fact that inside the operator log is an lvalue and can bind to a non-const reference of the other operators.

Related

Implicit conversion free function [duplicate]

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>();
...

std::function as template parameter

I currently have a map<int, std::wstring>, but for flexibility, I want to be able to assign a lambda expression, returning std::wstring as value in the map.
So I created this template class:
template <typename T>
class ValueOrFunction
{
private:
std::function<T()> m_func;
public:
ValueOrFunction() : m_func(std::function<T()>()) {}
ValueOrFunction(std::function<T()> func) : m_func(func) {}
T operator()() { return m_func(); }
ValueOrFunction& operator= (const T& other)
{
m_func = [other]() -> T { return other; };
return *this;
}
};
and use it like:
typedef ValueOrFunction<std::wstring> ConfigurationValue;
std::map<int, ConfigurationValue> mymap;
mymap[123] = ConfigurationValue([]() -> std::wstring { return L"test"; });
mymap[124] = L"blablabla";
std::wcout << mymap[123]().c_str() << std::endl; // outputs "test"
std::wcout << mymap[124]().c_str() << std::endl; // outputs "blablabla"
Now, I don't want to use the constructor for wrapping the lambda, so I decided to add a second assignment operator, this time for the std::function:
ValueOrFunction& operator= (const std::function<T()>& other)
{
m_func = other;
return *this;
}
This is the point where the compiler starts complaining. The line mymap[124] = L"blablabla"; suddenly results in this error:
error C2593: 'operator = is ambiguous'
IntelliSense gives some more info:
more than one operator "=" matches these operands: function
"ValueOrFunction::operator=(const std::function &other) [with
T=std::wstring]" function "ValueOrFunction::operator=(const T
&other) [with T=std::wstring]" operand types are: ConfigurationValue =
const wchar_t
[10] c:\projects\beta\CppTest\CppTest\CppTest.cpp 37 13 CppTest
So, my question is, why isn't the compiler able to distinguish between std::function<T()> and T? And how can I fix this?
The basic problem is that std::function has a greedy implicit constructor that will attempt to convert anything, and only fail to compile in the body. So if you want to overload with it, either no conversion to the alternative can be allowed, of you need to disable stuff that can convert to the alternative from calling the std::function overload.
The easiest technique would be tag dispatching. Make an operator= that is greedy and set up for perfect forwarding, then manually dispatch to an assign method with a tag:
template<typename U>
void operator=(U&&u){
assign(std::forward<U>(u), std::is_convertible<U, std::wstring>());
}
void assign(std::wstring, std::true_type /*assign_to_string*/);
void assign(std::function<blah>, std::false_type /*assign_to_non_string*/);
basically we are doing manual overload resolution.
More advanced techniques: (probably not needed)
Another approach would be to limit the std::function = with SFINAE on the argument being invoked is valid, but that is messier.
If you have multiple different types competing with your std::function you have to sadly manually dispatch all of them. The way to fix that is to test if your type U is callable with nothing and the result convertible to T, then tag dispatch on that. Stick the non-std::function overloads in the alternative branch, and let usual more traditional overloading to occur for everything else.
There is a subtle difference in that a type convertible to both std::wstring and callable returning something convertible to T ends up being dispatched to different overloads than the original simple solution above, because the tests used are not actually mutually exclusive. For full manual emulation of C++ overloading (corrected for std::functions stupidity) you need to make that case ambiguous!
The last advanced thing to do would be to use auto and trailing return types to improve the ability of other code to detect if your = is valid. Personally, I would not do this before C++14 except under duress, unless I was writing some serious library code.
Both std::function and std::wstring have conversion operators that could take the literal wide string you are passing. In both cases the conversions are user defined and thus the conversion sequence takes the same precedence, causing the ambiguity. This is the root cause of the error.

Why is this cast ambiguous?

I have a class that I have written which does type erasure. The public interface is:
template <typename T>
value(const T &t);
value(value &&v);
template <typename T>
operator T() const;
When I create a value instance from a std::string I have no problems, everything works as expected. When I try to get the std::string back out, using static_cast<std::string>(val), where val is an instance of value that is holding a std::string, I get the following error from VS2012:
error C2440: 'static_cast' : cannot convert from 'value' to std::string'
No constructor could take the source type, or constructor overload resolution was ambiguous
If I comment out the templated cast operator and add operator std::string() const then it compiles. I figure that something between the std::string constructors and the templated cast operator have the same goodness of match. Could anyone suggest what is happening and how to fix it?
Igor explained the problem. Here's my suggested solution:
Your class is obviously only intended to store one type of object at a time, so make that explicit. Replace the conversion functions with a real function:
template <typename T>
T get() const;
Now call it like this:
std::string myString = myValue.get<std::string>( );
No ambiguity. No chance of the wrong function being called and messing everything up. And I'd argue that it is now more readable.
std::string has several constructors capable of being called with one parameter - e.g. one taking const string&, and another taking const char*. What should T resolve to, then?
From the C++ standard:
5.2.9p4 Otherwise, an expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t.
In your case, the declaration std::string t(val); is ill-formed.
Following works with std::string (if you can return a reference).
static_cast<const std::string&>(val);

C++ nested referece directly vs via template argument

Just a question something I found interesting when working with stl. In the below code, the last two lines in the main function will cause the error (indicated in the comments). However, the test_func compiles fine. Since type being passed to the template function is a reference type and the function itself applies the & operator aren't these two things essentially the same? well, apparently not cause one of them compiles and the other doesn't. Anyone know why?
class File {
private:
std::string name_;
public:
File(std::string n) : name_(n) {}
std::string name() const { return name_; }
};
std::ostream& operator<<(std::ostream& os, const File& f)
{
os << f.name();
return os;
}
template <class T> void test_func(const T& v)
{
T& v1(v);
std::cout << "File:" << v1 << std::endl;
}
typedef File& FileRef;
int main(int argc, char* argv[])
{
File f("test_file");
test_func<File&>(f);
// FileRef& fRef1(f); ==> error; cannot declare reference to 'class File&'
// File&& fRef2(f); ==> error; expected unqualified-id before '&&' token
}
UPDATE: I came across this when working with bind1st and bind2nd functions in ; they are defined just like test_func in the text book (stroustrup in Chapter 18 section on binders) so it can't be wrong.
The first commented line is legal, and your compiler is probably not conforming with C++11. Because of C++11's reference collapsing rules, in fact, it should declare an lvalue reference to File named fRef1 and bind it to the lvalue f.
The second commented line is illegal: you cannot bind an rvalue reference to an lvalue. However, the error you are getting seems to indicate that the compiler does not understand the && token.
If you are using Clang or GCC, make sure you are compiling with the -std=c++11 or -std=c++0x option.
UPDATE:
In C++03, both lines are illegal, and even this function call should be rejected by the compiler:
test_func<File&>(f); // SHOULD BE AN ERROR! (substitution failure)
Per paragraph 14.8.2/2 of the C++03 Standard:
[...] Type deduction may fail for
the following reasons:
— [...]
— Attempting to create a reference to a reference type or a reference to void.
— [...]
This can mean two things: either your compiler has a bug, or it intentionally decides to ignore an attempt to create a reference to reference in the context of template argument deduction (and only in that context) - meaning that you're dealing with a compiler extension.
In any case, that function call is ill-formed and therefore not portable.
I think the function works, because the compiler is clever enough not to make a reference of a reference. He gets a reference and wants a reference, so it stays one. I think he simply ignores the second & when you have T& with T already a reference.
I can't explain it in detail but in c++ you can use references mostly exactly like non-references.
In FileRef& he can't ignore that. Here you explicitly say: make a reference of a reference, what can't work.
And && is a logical AND.
ps: substitution failure is not an error (SFINAE)

Overloading the global type conversion operator

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>();
...