Unable to find operator via implicit conversion in C++ - c++

When writing a class to act as a wrapper around a heap-allocated object, I encountered a problem with implicit type conversion that can be reduced to this simple example.
In the code below the wrapper class manages a heap-allocated object and implicitly converts to a reference to that object. This allows the wrapper object to be passed as the argument to the function write(...) since implicit conversion takes place.
The compiler fails, however, when trying to resolve the call to operator<<(...), unless an explicit cast is made (checked with MSVC8.0, Intel 9.1 and gcc 4.2.1 compilers).
So, (1) why does the implicit conversion fail in this case? (2) could it be related to argument-dependent lookup? and (3) is there anything that can be done to make this work without the explicit cast?
#include <fstream>
template <typename T>
class wrapper
{
T* t;
public:
explicit wrapper(T * const p) : t(p) { }
~wrapper() { delete t; }
operator T & () const { return *t; }
};
void write(std::ostream& os)
{
os << "(1) Hello, world!\n";
}
int main()
{
wrapper<std::ostream> file(new std::ofstream("test.txt"));
write(file);
static_cast<std::ostream&>( file ) << "(2) Hello, world!\n";
// file << "(3) This line doesn't compile!\n";
}

It fails because you're trying to resolve an operator of your wrapper<T> class that doesn't exist. If you want it to work without the cast, you could put together something like this:
template<typename X> wrapper<T> &operator <<(X &param) const {
return t << param;
}
Unfortunately I don't know of a way to resolve the return type at compile time. Fortunately in most cases it's the same type as the object, including in this case with ostream.
EDIT: Modified code by suggestion from dash-tom-bang. Changed return type to wrapper<T> &.

The compiler doesn't have enough context to determine that operator& will make a valid conversion. So, yes, I think this is related to argument-dependent lookup: The compiler is looking for an operator<< that can accept a non-const wrapper<std::ostream> as its first parameter.

I think the problem has to do with maintaining some compile-time constraints. In your example, the compiler first would have to find all the possible operator<<. Then, for each of them, it should try if your object could be automatically converted (directly or indirectly) to any of the types that each operator<< are able to accept.
This test can be really complex, and I think this is restricted to provide a reasonable compiling time.

After some testing, an even simpler example identifies the source of the problem. The compiler cannot deduce the template argument T in f2(const bar<T>&) below from implicit conversion of wrapper<bar<int> > to bar<int>&.
template <typename T>
class wrapper
{
T* t;
public:
explicit wrapper(T * const p) : t(p) { }
~wrapper() { delete t; }
operator T & () const { return *t; }
};
class foo { };
template <typename T> class bar { };
void f1(const foo& s) { }
template <typename T> void f2(const bar<T>& s) { }
void f3(const bar<int>& s) { }
int main()
{
wrapper<foo> s1(new foo());
f1(s1);
wrapper<bar<int> > s2(new bar<int>());
//f2(s2); // FAILS
f2<int>(s2); // OK
f3(s2);
}
In the original example, std::ostream is actually a typedef for the templated class std::basic_ostream<..>, and the same situation applies when calling the templated function operator<<.

Check the signature of the insertion operator... I think they take non-const ostream reference?
Confirmed with C++03 standard, signature of the char* output operator is:
template<class charT, class traits>
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
which does indeed take a non-const reference. So your conversion operator does not match.
As noted in the comment: this is irrelevant.
There are various limits in the Standard about conversions applied... maybe this would need to implicit conversions (your operator, and cast to base type) when at most one should be applied.

Related

Use of rvalue references in function parameter of overloaded function creates too many combinations

Imagine you have a number of overloaded methods that (before C++11) looked like this:
class MyClass {
public:
void f(const MyBigType& a, int id);
void f(const MyBigType& a, string name);
void f(const MyBigType& a, int b, int c, int d);
// ...
};
This function makes a copy of a (MyBigType), so I want to add an optimization by providing a version of f that moves a instead of copying it.
My problem is that now the number of f overloads will duplicate:
class MyClass {
public:
void f(const MyBigType& a, int id);
void f(const MyBigType& a, string name);
void f(const MyBigType& a, int b, int c, int d);
// ...
void f(MyBigType&& a, int id);
void f(MyBigType&& a, string name);
void f(MyBigType&& a, int b, int c, int d);
// ...
};
If I had more parameters that could be moved, it would be unpractical to provide all the overloads.
Has anyone dealt with this issue? Is there a good solution/pattern to solve this problem?
Thanks!
Herb Sutter talks about something similar in a cppcon talk
This can be done but probably shouldn't. You can get the effect out using universal references and templates, but you want to constrain the type to MyBigType and things that are implicitly convertible to MyBigType. With some tmp tricks, you can do this:
class MyClass {
public:
template <typename T>
typename std::enable_if<std::is_convertible<T, MyBigType>::value, void>::type
f(T&& a, int id);
};
The only template parameter will match against the actual type of the parameter, the enable_if return type disallows incompatible types. I'll take it apart piece by piece
std::is_convertible<T, MyBigType>::value
This compile time expression will evaluate to true if T can be converted implicitly to a MyBigType. For example, if MyBigType were a std::string and T were a char* the expression would be true, but if T were an int it would be false.
typename std::enable_if<..., void>::type // where the ... is the above
this expression will result in void in the case that the is_convertible expression is true. When it's false, the expression will be malformed, so the template will be thrown out.
Inside the body of the function you'll need to use perfect forwarding, if you are planning on copy assigning or move assigning, the body would be something like
{
this->a_ = std::forward<T>(a);
}
Here's a coliru live example with a using MyBigType = std::string. As Herb says, this function can't be virtual and must be implemented in the header. The error messages you get from calling with a wrong type will be pretty rough compared to the non-templated overloads.
Thanks to Barry's comment for this suggestion, to reduce repetition, it's probably a good idea to create a template alias for the SFINAE mechanism. If you declare in your class
template <typename T>
using EnableIfIsMyBigType = typename std::enable_if<std::is_convertible<T, MyBigType>::value, void>::type;
then you could reduce the declarations to
template <typename T>
EnableIfIsMyBigType<T>
f(T&& a, int id);
However, this assumes all of your overloads have a void return type. If the return type differs you could use a two-argument alias instead
template <typename T, typename R>
using EnableIfIsMyBigType = typename std::enable_if<std::is_convertible<T, MyBigType>::value,R>::type;
Then declare with the return type specified
template <typename T>
EnableIfIsMyBigType<T, void> // void is the return type
f(T&& a, int id);
The slightly slower option is to take the argument by value. If you do
class MyClass {
public:
void f(MyBigType a, int id) {
this->a_ = std::move(a); // move assignment
}
};
In the case where f is passed an lvalue, it will copy construct a from its argument, then move assign it into this->a_. In the case that f is passed an rvalue, it will move construct a from the argument and then move assign. A live example of this behavior is here. Note that I use -fno-elide-constructors, without that flag, the rvalue cases elides the move construction and only the move assignment takes place.
If the object is expensive to move (std::array for example) this approach will be noticeably slower than the super-optimized first version. Also, consider watching this part of Herb's talk that Chris Drew links to in the comments to understand when it could be slower than using references. If you have a copy of Effective Modern C++ by Scott Meyers, he discusses the ups and downs in item 41.
You may do something like the following.
class MyClass {
public:
void f(MyBigType a, int id) { this->a = std::move(a); /*...*/ }
void f(MyBigType a, string name);
void f(MyBigType a, int b, int c, int d);
// ...
};
You just have an extra move (which may be optimized).
My first thought is that you should change the parameters to pass by value. This covers the existing need to copy, except the copy happens at the call point rather than explicitly in the function. It also allows the parameters to be created by move construction in a move-able context (either unnamed temporaries or by using std::move).
Why you would do that
These extra overloads only make sense, if modifying the function paramers in the implementation of the function really gives you a signigicant performance gain (or some kind of guarantee). This is hardly ever the case except for the case of constructors or assignment operators. Therefore, I would advise you to rethink, whether putting these overloads there is really necessary.
If the implementations are almost identical...
From my experience this modification is simply passing the parameter to another function wrapped in std::move() and the rest of the function is identical to the const & version. In that case you might turn your function into a template of this kind:
template <typename T> void f(T && a, int id);
Then in the function implementation you just replace the std::move(a) operation with std::forward<T>(a) and it should work. You can constrain the parameter type T with std::enable_if, if you like.
In the const ref case: Don't create a temporary, just to to modify it
If in the case of constant references you create a copy of your parameter and then continue the same way the move version works, then you may as well just pass the parameter by value and use the same implementation you used for the move version.
void f( MyBigData a, int id );
This will usually give you the same performance in both cases and you only need one overload and implementation. Lots of plusses!
Significantly different implementations
In case the two implementations differ significantly, there is no generic solution as far as I know. And I believe there can be none. This is also the only case, where doing this really makes sense, if profiling the performance shows you adequate improvements.
You might introduce a mutable object:
#include <memory>
#include <type_traits>
// Mutable
// =======
template <typename T>
class Mutable
{
public:
Mutable(const T& value) : m_ptr(new(m_storage) T(value)) {}
Mutable(T& value) : m_ptr(&value) {}
Mutable(T&& value) : m_ptr(new(m_storage) T(std::move(value))) {}
~Mutable() {
auto storage = reinterpret_cast<T*>(m_storage);
if(m_ptr == storage)
m_ptr->~T();
}
Mutable(const Mutable&) = delete;
Mutable& operator = (const Mutable&) = delete;
const T* operator -> () const { return m_ptr; }
T* operator -> () { return m_ptr; }
const T& operator * () const { return *m_ptr; }
T& operator * () { return *m_ptr; }
private:
T* m_ptr;
char m_storage[sizeof(T)];
};
// Usage
// =====
#include <iostream>
struct X
{
int value = 0;
X() { std::cout << "default\n"; }
X(const X&) { std::cout << "copy\n"; }
X(X&&) { std::cout << "move\n"; }
X& operator = (const X&) { std::cout << "assign copy\n"; return *this; }
X& operator = (X&&) { std::cout << "assign move\n"; return *this; }
~X() { std::cout << "destruct " << value << "\n"; }
};
X make_x() { return X(); }
void fn(Mutable<X>&& x) {
x->value = 1;
}
int main()
{
const X x0;
std::cout << "0:\n";
fn(x0);
std::cout << "1:\n";
X x1;
fn(x1);
std::cout << "2:\n";
fn(make_x());
std::cout << "End\n";
}
This is the critical part of the question:
This function makes a copy of a (MyBigType),
Unfortunately, it is a little ambiguous. We would like to know what is the ultimate target of the data in the parameter. Is it:
1) to be assigned to an object that existing before f was called?
2) or instead, stored in a local variable:
i.e:
void f(??? a, int id) {
this->x = ??? a ???;
...
}
or
void f(??? a, int id) {
MyBigType a_copy = ??? a ???;
...
}
Sometimes, the first version (the assignment) can be done without any copies or moves. If this->x is already long string, and if a is short, then it can efficiently reuse the existing capacity. No copy-construction, and no moves. In short, sometimes assignment can be faster because we can skip the copy contruction.
Anyway, here goes:
template<typename T>
void f(T&& a, int id) {
this->x = std::forward<T>(a); // is assigning
MyBigType local = std::forward<T>(a); // if move/copy constructing
}
If the move version will provide any optimization then the implementation of the move overloaded function and the copy one must be really different. I don't see a way to get around this without providing implementations for both.

C++ - Using a template to return a const reference publicly and a non const reference privately

The question: How can I make it so that a const reference is returned publicly and a non const reference returned privately?
I'm trying to create a read-only template for some variables in my classes. This involves a template class which returns a const reference to the data when public. However in the class I need to operate on the data so I am trying to return a reference that is not const privately. Here's the basics:
private: operator T&() { return data; }
public: operator const T&() const { return data; }
When I add the non const reference as shown above, if I try to access the variable publicly my Visual Studio 2010 cl.exe compiler tells me it cannot access the private member in the class. Something as simple as cout << myobj.x << endl if x was declared using the template will fail.
error C2248: 'proxy<T,C>::operator int &' : cannot access private member declared in class 'proxy<T,C>'
Here is the other thread for reference:
C++ - How to make read only class member variables in Visual Studio 2010 - Stack Overflow
Edit:
You asked for the code so here it is.
template <class T, class C>
class proxy {
friend C;
private:
T data;
T operator=(const T& arg) { data = arg; return data; }
operator T&() { return data; } // I'd expect this is only returned privately
public:
operator const T&() const { return data; }
};
class myClass {
public:
proxy<int,myClass> x;
void f(int i) {
x = i;
}
};
int main(int argc, char **argv)
{
myClass test;
test.f(12);
cout << test.x << endl; // Compiler error trying to access non-const T&
return 0;
}
Actually, visibility and accesibility are independent things in C++:
Visibility rules say that all the member functions are considered when resolving an overload.
Accesibility means that if the chosen overload function is not accesible from the used context (private member from outside of the class, for example) a compiler error will happen.
Some people think that private members will not participate in overload resolution if the function in called from outside of the class, but that's not the case. All functions, irrespective of the access, are considered.
About your specific problem, you do:
std::cout << test.x;
Here test is non-const, so is test.x, and of the two overload conversion functions, the non-const one is chosen. But, alas, this function is private, thus compiler error.
The quick solution is to do a const_cast:
std::cout << const_cast<const myClass&>(test).x;
Or if you prefer:
const myClass &ctest = test;
std::cout << ctest.x;
The right solution would be to just remove the non-const private one. You don't need it, since from the class context you can use the data member directly.
Frankly, it looks like you are trying to implement properties in C++ using the syntax from other languages. Properties are fine, but that's not the C++ way.
My advice is: do not fight the language, accept the syntax as it is, and just do the parenthesis thing. Or if x does not hold an invariant, just do it public.
The shortest way would be something like:
class myClass {
private:
int _x;
public:
int x() const {
return _x;
}
//if needed
void x(int value) {
_x = value;
}
};
The people that will read your code in the future (mind you, it might be me!) will greatly appreciate that you do not try and reinvent the language.
In C++, access checks are done after overload resolution. This has both advantages and disadvantages over the other possibility -- removing inaccessible functions from the candidate set.
Usually the solution is to use a different name for the private function. But it appears that you're trying to conform to a particular interface required by some functions you've befriended. I don't think there's an easy workaround for that. Private inheritance won't help in the general case, because inherited functions aren't part of the candidate set, they're hidden by a function in the derived class. But conversion functions are inherited... and after testing, it seems that the original problem recurs (even a private conversion in a private base class is found).
So I finally suggest using a named function instead of a conversion, as in:
template <typename T, typename C>
class proxy
{
friend C;
private:
T data;
T operator=(const T& arg) { data = arg; return data; }
T& mutate() { return data; }
public:
operator const T&() const { return data; }
};
class myClass
{
public:
proxy<int,myClass> x;
void f(int i)
{
x.mutate() = i;
}
};
test is not const, test.x is not const, so myClass::operator int() is a better match that myClass::operator int() const.
Access control (private/public) doesn't enter into it.

Explicit conversion and templated conversion operator

I wanted to somehow extend the Microsoft type _variant_t so it accepts implicit/explicit conversions to/from additional types. To do so, I wrote the following class:
class value_type
{
public:
/* Constructors */
value_type(const std::string& str) : m_variant(str.c_str()) {}
template <typename Type> value_type(const Type& value) : m_variant(value) {}
/* Conversion operators */
operator const _variant_t&() const { return m_variant; }
operator std::string() const { return static_cast<const char*>(m_variant); }
template <typename Type> operator Type() const { return static_cast<Type>(m_variant); }
private:
_variant_t m_variant;
};
That is, if every instance of _variant_t in the code is replaced with value_type, it "works" the same.
Lets consider the following function, which returns a _variant_t:
_variant_t foo();
If I write:
std::string bar()
{
value_type v = foo();
return v;
}
It compiles just fine.
But if I change the previous code like that:
std::string bar()
{
return value_type(foo());
}
or:
std::string bar()
{
return static_cast<std::string>(value_type(foo()));
}
The compilation fails with the following message:
configuration.cpp(41) : error C2668: 'std::basic_string<_Elem,_Traits,_Ax>::basic_string' : ambiguous call to overloaded function
If I remove the template <typename Type> operator Type... line, everything compiles.
Now I understand what the compilater says (it doesn't know which operator to use) but I don't understand why: It would seem logical to use the operator std::string when converting to std::string. What am I missing ?
Thank you.
The problem is that string's constructor is overloaded. So if returning involves invoking a string constructor, then there are multiple choices: argument could be converted to const char*, allocator<char> or string.
static_cast<string>(x) is the same as string(x).
I suppose your first faulty example should read return string(foo());, not return value_type(foo());

What are the use cases for having a function return by const value for non-builtin type?

Recently I have read that it makes sense when returning by value from a function to qualify the return type const for non-builtin types, e.g.:
const Result operation() {
//..do something..
return Result(..);
}
I am struggling to understand the benefits of this, once the object has been returned surely it's the callers choice to decide if the returned object should be const?
Basically, there's a slight language problem here.
std::string func() {
return "hai";
}
func().push_back('c'); // Perfectly valid, yet non-sensical
Returning const rvalues is an attempt to prevent such behaviour. However, in reality, it does way more harm than good, because now that rvalue references are here, you're just going to prevent move semantics, which sucks, and the above behaviour will probably be prevented by the judicious use of rvalue and lvalue *this overloading. Plus, you'd have to be a bit of a moron to do this anyway.
It is occasionally useful. See this example:
class I
{
public:
I(int i) : value(i) {}
void set(int i) { value = i; }
I operator+(const I& rhs) { return I(value + rhs.value); }
I& operator=(const I& rhs) { value = rhs.value; return *this; }
private:
int value;
};
int main()
{
I a(2), b(3);
(a + b) = 2; // ???
return 0;
}
Note that the value returned by operator+ would normally be considered a temporary. But it's clearly being modified. That's not exactly desired.
If you declare the return type of operator+ as const I, this will fail to compile.
There is no benefit when returning by value. It doesn't make sense.
The only difference is that it prevents people from using it as an lvalue:
class Foo
{
void bar();
};
const Foo foo();
int main()
{
foo().bar(); // Invalid
}
Last year I've discovered another surprising usecase while working on a two-way C++-to-JavaScript bindings.
It requires a combination of following conditions:
You have a copyable and movable class Base.
You have a non-copyable non-movable class Derived deriving from Base.
You really, really do not want an instance of Base inside Derived to be movable as well.
You, however, really want slicing to work for whatever reason.
All classes are actually templates and you want to use template type deduction, so you cannot really use Derived::operator const Base&() or similar tricks instead of public inheritance.
#include <cassert>
#include <iostream>
#include <string>
#include <utility>
// Simple class which can be copied and moved.
template<typename T>
struct Base {
std::string data;
};
template<typename T>
struct Derived : Base<T> {
// Complex class which derives from Base<T> so that type deduction works
// in function calls below. This class also wants to be non-copyable
// and non-movable, so we disable copy and move.
Derived() : Base<T>{"Hello World"} {}
~Derived() {
// As no move is permitted, `data` should be left untouched, right?
assert(this->data == "Hello World");
}
Derived(const Derived&) = delete;
Derived(Derived&&) = delete;
Derived& operator=(const Derived&) = delete;
Derived& operator=(Derived&&) = delete;
};
// assertion fails when the `const` below is commented, wow!
/*const*/ auto create_derived() { return Derived<int>{}; }
// Next two functions hold reference to Base<T>/Derived<T>, so there
// are definitely no copies or moves when they get `create_derived()`
// as a parameter. Temporary materializations only.
template<typename T>
void good_use_1(const Base<T> &) { std::cout << "good_use_1 runs" << std::endl; }
template<typename T>
void good_use_2(const Derived<T> &) { std::cout << "good_use_2 runs" << std::endl; }
// This function actually takes ownership of its argument. If the argument
// was a temporary Derived<T>(), move-slicing happens: Base<T>(Base<T>&&) is invoked,
// modifying Derived<T>::data.
template<typename T>
void oops_use(Base<T>) { std::cout << "bad_use runs" << std::endl; }
int main() {
good_use_1(create_derived());
good_use_2(create_derived());
oops_use(create_derived());
}
The fact that I did not specify the type argument for oops_use<> means that the compiler should be able to deduce it from argument's type, hence the requirement that Base<T> is actually a real base of Derived<T>.
An implicit conversion should happen when calling oops_use(Base<T>). For that, create_derived()'s result is materialized into a temporary Derived<T> value, which is then moved into oops_use's argument by Base<T>(Base<T>&&) move constructor. Hence, the materialized temporary is now moved-from, and the assertion fails.
We cannot delete that move constructor, because it will make Base<T> non-movable. And we cannot really prevent Base<T>&& from binding to Derived<T>&& (unless we explicitly delete Base<T>(Derived<T>&&), which should be done for all derived classes).
So, the only resolution without Base modification here is to make create_derived() return const Derived<T>, so that oops_use's argument's constructor cannot move from the materialized temporary.
I like this example because not only it compiles both with and without const without any undefined behaviour, it behaves differently with and without const, and the correct behavior actually happens with const only.

How to create a "default" stream insertion operator in C++?

I have a class similar to boost::any, in that it is a templated container class. I'd like to have a method to write the contained value to a string. However, if the contained type doesn't provide a stream insertion operator, I'd like my method to return some default tring rather than failing to compile. Below is as close as I've come, and should make it clear as to what I'm trying to do:
namespace W {
namespace hide {
template <typename T>
std::ostream& operator<<(std::ostream& out, const T& t) {
return std::operator<<(out, typeid(T).name());
}
}
template <typename T> struct C {
T t_;
std::string ToString() const {
using namespace hide;
std::ostringstream oss;
oss << t_;
return oss.str();
}
};
}
This works pretty well, with some caveats. For example, if I want to actually provide an overloaded insertion operator for a class, then that operator has to either be in the same namespace as the class, or it has to be in the W namespace for it to be considered.
It also has problems with any type that already has a non-member std::operator<<, e.g. char and std::string. If T is one of those types, then the oss << t_ line above becomes ambiguous. This can be worked around by adding overloads for these types inside the W namespace, for example:
std::ostream& operator << (std::ostream& out, const std::string& s) {
return std::operator <<(out, s);
}
My question is, has anyone found a better method than this? Why do I have to add my own overloads for things like std::string? Is this all supported according to the standard, or am I taking advantage of non-standard behavior? (I am testing with g++ 4.3.3)
Below is some code that I recall seeing a while ago in a compiler construction class. I thought it was particularly clever (if not 'clean') so I held on to it.
From http://www.cs.colorado.edu/~main/a++/tree.h
// If data of type T can be printed with the usual << operator, then
// print<T>(out, p) will interpret *p as a T object and print its
// value to out. Otherwise, a message is printed to out, indicating
// that objects of type T are not printable.
template<typename T> void print(std::ostream& out, const void* p)
{
// The first part of this code sets an enum value, is_printable, to
// be 1 if the data type T can be printed with the usual <<
// operator. Otherwise, is_printable is set to zero. The programming
// technique is based on a note from Herb Sutter at
// http://www.gotw.ca/gotw/071.htm
class object
{
public:
object(T convert) { };
};
char operator << (std::ostream&, const object&);
enum { is_printable = sizeof(std::cout << (*static_cast<T*>(0))) == sizeof(char) ? 0 : 1 };
// Notice that the boolean expression in the if-statement is known at
// compile time, so that only one of the two output statements will be
// compiled into object code.
if (is_printable)
out << *static_cast<const T*>(p);
else
out << "(value of type " << typeid(T).name() << " cannot be printed)";
}
When you construct your container object, hold a pointer to the print function for the variable:
void (*printer)(std::ostream&, const void*);
printer = print<T>;
Then later use the printer() function to display the contained value if possible.
Hope this helps.