C++ type coercion deduction - c++

I'm playing around with the Colvin-Gibbons trick for implementing move semantics in C++03 and I've got the following:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
template <typename T>
class buffer {
struct buffer_ref {
buffer_ref(T* data) : data_(data) {}
T* data_;
};
public:
buffer() : data_(NULL) {}
//explicit buffer(T* data) : data_(data) {}
buffer(size_t size) : data_(new T[size]) {}
buffer(buffer_ref other) : data_(other.data_) { other.data_ = NULL; }
buffer(buffer &other) : data_(other.data_) { other.data_ = NULL; }
~buffer() { delete [] data_; }
operator buffer_ref() { buffer_ref ref(data_); data_ = NULL; return ref; }
operator T*() { return data_; }
private:
T* data_;
};
int main() {
buffer<float> data(buffer<float>(128));
printf("ptr: %p\n", (float*)data);
}
Edit: formatting
I'd like to be able to use my buffer as a pointer to the base type when convenient, so I've added a casting operator to the pointer type, which works just as expected. However, if I uncomment my constructor that takes a pointer, then the the conversion deduction gets confused and complains about ambiguous conversion (because it can go buffer->T*->buffer or buffer->buffer_ref->buffer). I would expect an explicit modifier on the pointer constructor to fix this, but it doesn't. Can someone who understands the C++ conversion deduction better than me explain what the compilers thinking?

This is a direct result of 13.3.1.3 [over.match.ctor]:
When objects of class type are direct-initialized (8.5), or copy-initialized from an expression of the same or a derived class type (8.5), overload resolution selects the constructor. For direct-initialization, the candidate functions are all the constructors of the class of the object being initialized. For copy-initialization, the candidate functions are all the converting constructors (12.3.1) of that class. [...]
Because buffer<float> data(buffer<float>(128)); is a direct-initialization, you have explicitly requested that explicit constructors be considered.
If you write:
buffer<float> data = buffer<float>(128);
then there is no ambiguity.

Related

Deleting all lvalue conversion operators

I want to avoid all lvalue conversions from a type to another type:
struct A
{};
struct T
{
A a;
operator A() { return a; }
//operator A&() = delete; how to delete lvalue conversions to A?
};
void bar(A)
{}
void foo(const A&)
{}
void foo2(A&)
{}
int main()
{
T t;
bar(t); // fine
foo(t); // should never convert to ref-to-const A
foo2(t); // should never convert to ref-to A
return 0;
}
Is this possible?
How and which conversion operators do I need to delete?
Example on godbolt
You might do
struct T
{
A a;
operator A() { return a; }
template <typename T> operator const T&() = delete;
};
Demo

Template user defined conversions to abstract class reference and the Intel compiler

I have the following (very simplified) "container" class:
class container
{
public:
template<typename T> container(const boost::shared_ptr<T> &rhs)
: m_content(rhs) { }
template<typename T>
operator T const & () const
{
return get<T>();
}
template<typename T>
T const & get() const
{
return *boost::any_cast< boost::shared_ptr<T> >(m_content);
}
private:
boost::any m_content;
};
It should store objects in the boost::any container in the form of a shared pointer. If I store some object, say, of the boost::shared_ptr<some_type> type in the container, I would like to get the reference (const some_type&) simply by a user-defined conversion which would allow to do something like this:
boost::shared_ptr<some_type> x(new some_type);
container cx = x;
...
// user-defined conversion
const some_type &y = cx;
// a template conversion using a "getter"
const some_type &y = cx.get<some_type>();
Sometimes, I need to store objects derived from some abstract type and do the same sort of type conversion to the reference of this abstract type, for example, like this:
boost::shared_ptr<some_abstract_type> x(new some_derived_type);
container cx = x;
...
// user-defined conversion
const some_abstract_type &y = cx;
// a template conversion using a "getter"
const some_abstract_type &y = cx.get<some_abstract_type>();
Both the user-defined conversion and the template "getter" work fine with GCC. However, the Intel C++ compiler seems to have a problem with the (user-defined) conversion while the "getter" works.
For example, the following code works with GCC but not with Intel:
#include <iostream>
#include <boost/any.hpp>
#include <boost/shared_ptr.hpp>
class container
{
public:
template<typename T> container(const boost::shared_ptr<T> &rhs)
: m_content(rhs) { }
template<typename T>
operator T const & () const
{
return get<T>();
}
template<typename T>
T const & get() const
{
return *boost::any_cast< boost::shared_ptr<T> >(m_content);
}
private:
boost::any m_content;
};
class base
{
public:
virtual ~base() { }
virtual void f() const = 0;
};
class derived : public base
{
public:
virtual ~derived() { }
virtual void f() const { std::cout << "hello\n"; }
};
void foo(const container &c)
{
const base & a = c;
a.f();
}
int main()
{
boost::shared_ptr<base> a(new derived);
container c = a;
foo(c);
}
With Intel, I get this error:
test.cpp(44): error: no suitable user-defined conversion from "const container" to "const base" exists
const base & a = c;
^
compilation aborted for test.cpp (code 2)
On the other hand, if I replace base with derived in both main() and foo() (or use the "getter" instead of the type conversion in foo()), everything works fine with Intel too. Is it possible to convince the Intel compiler to use the user-defined type conversion to the reference type when T is an abstract class?
Thanks in advance for any ideas.
EDIT: Interestingly, using the type conversion to the pointer type works fine. If I add
template<typename T>
operator T const * () const
{
return &get<T>();
}
to the container class and replace foo() with
void foo(const container &c)
{
const base * a = c;
a->f();
}
then it works also with Intel.
I would return a pointer in the getter:
template<typename T>
T const * get() const {
return boost::any_cast< boost::shared_ptr<T> >(m_content);
}
This avoids the conversion problem, and does not crash immediately if you pass a null pointer to your container.
Example:
void foo(const container &c)
{
const base* a = c.get<base>();
a->f();
}
You could also add a function valid() which checks if there is something in the container:
bool valid() const {
return m_content != NULL;
}
Edit: Your addition to your question follows exactly in this direction.
Ok, so it seems that it is a bug in the Intel C++ compiler and was filed in the bug tracking list.

boost::in_place taking arguments as const refs

I have a class where the constructor takes parameter as reference. For eg.
class A
{
A(Tracer& t) : m_t(t) { }
private:
Tracer& m_t;
};
I have this class A as boost::optional and want to construct it only when needed. If I use boost::in_place to construct it. Since boost::in_place takes the parameters as const_refs, I had to modify the signature of the constructor to
A(const Tracer& t) : m_t(const_cast<Tracer&>(t) { }
is there any other way of passing the object by reference ?
The s/w limitation is boost 1.4.3, VS2010.
EDIT: The class is not copy-constructible and assignable as well. I haven't showed that in the sample class mentioned above.
Like this:
#include <boost/optional.hpp>
#include <boost/ref.hpp>
struct Tracer
{
Tracer() = default;
Tracer(const Tracer&) = delete;
Tracer(Tracer&&) = delete;
Tracer& operator=(const Tracer&) = delete;
Tracer& operator=(Tracer&&) = delete;
};
class A
{
public: // Note: I had to add this.
A(Tracer& t) : m_t(t) { }
private:
Tracer& m_t;
};
int main()
{
Tracer tracer;
boost::optional<A> x;
x = boost::in_place(boost::ref(tracer));
}
boost::ref returns a boost::reference_wrapper, which models a reference as a value.

Implicit conversions in C++

Given the following code, why doesn't the compiler resolve the implicit conversion when constructing Bar? That is, construct Foo just like a was constructed which is (should) then be used to construct Bar?
#include <string>
class ImplicitlyConvertToChar
{
public:
ImplicitlyConvertToChar(const char* a_char)
: m_string(a_char)
{ }
ImplicitlyConvertToChar(const char* a_char, size_t a_end)
: m_string(a_char)
{
}
template <typename T_String>
ImplicitlyConvertToChar(T_String const& a_string)
: m_string(a_string.begin())
{
}
operator char const * () const
{ return m_string; }
const char* m_string;
};
class Foo
{
public:
Foo(const ImplicitlyConvertToChar& a_charLike)
: m_string(a_charLike)
{ }
const char* m_string;
};
class Bar
{
public:
Bar(const Foo& a_foo)
: m_foo(a_foo)
{ }
Foo m_foo;
};
int main()
{
Foo a("this works");
Bar b("Why doesn't this?");
}
You are not allowed more than one user defined implicit conversion. The Foo example involves one, the Bar example involves two.
The compiler is only allowed to make a single implicit user-defined conversion.
See http://en.cppreference.com/w/cpp/language/implicit_cast
A user-defined conversion consists of:
zero or one non-explicit single-argument constructor or non-explicit
conversion function calls
Constructing Bar that way would require two.

Interconvertible types and ambiguous calls

I have a sequence of types, which I want to be freely convertible to one another. Consider the following toy example:
struct A {
int value;
A(int v) : value(v) { }
};
struct B {
int value;
B(int v) : value(v) { }
B(A a) : value(a.value) { }
operator A() const { return A(value); }
};
struct C {
int value;
C(int v) : value(v) { }
C(A a) : value(a.value) { }
C(B b) : value(b.value) { }
operator B() const { return B(value); }
operator A() const { return A(B(*this)); } // <-- ambiguous
};
int main(int argc, const char** argv) {
C c(5);
A a(3);
a = c;
}
So as you see, I'm trying to defined each subsequent type to be convertible from all previous types using cast constructors, and to be convertible to all previous types using cast operators. Alas, this does not work as intended, as the definition of C::operator A is ambiguous according to gcc 4.7:
In member function ‘C::operator A() const’:
19:40: error: call of overloaded ‘B(const C&)’ is ambiguous
19:40: note: candidates are:
9:3: note: B::B(A)
6:8: note: constexpr B::B(const B&)
6:8: note: constexpr B::B(B&&)
Changing the expression to static_cast<A>(static_cast<B>(*this)) doesn't change a thing. Removing that line altogether results in an error message in main, as no implicit conversion sequence may use more than one user-defined conversion. In my toy example, I could perform the conversion from C to A direcly, but in my real life application, doing so would cause a lot of duplicate code, so I'd really like a solution which reuses the other conversion operators.
So how can I obtain a set of three freely interconvertible types without duplicating conversion code?
I'd try this way in struct C:
operator A() const { return this->operator B(); }
Try this:
operator A() const { return A(B(value)); }
or this:
operator A() const { return A(operator B()); }