Let we have a class with n fields. Each field can be moved. So do we have to explicitly define 2^n constructors?
The example with n=2:
struct A{
std::vector<B> a;
std::shared_ptr<B> b;
A(std::vector<B> &a, std::shared_ptr<B> &b):a(a),b(b){};
A(std::vector<B> &a, std::shared_ptr<B> &&b):a(a),b(std::move(b)){};
A(std::vector<B> &&a, std::shared_ptr<B> &b):a(std::move(a)),b(b){};
A(std::vector<B> &&a, std::shared_ptr<B> &&b):a(std::move(a)),b(std::move(b)){};
};
....
A aaa({{},{}}, shared_ptr<B>(new B()));
std::shared_ptr<B> b = ....;
A bbb({{},{}}, b);
You can work around it by having a perfect-forwarding template constructor:
struct A {
std::vector<B> a;
std::shared_ptr<B> b;
template <typename AA, typename BB> A(AA&& a, BB&& b) :
a(std::forward<AA>(a)), b(std::forward<BB>(b)) { }
};
If you need stricter parameter types requirement, you can also add enable_if or static_assert.
Here's a little explanation how perfect forwarding works:
void func1(int&&) { }
template <typename A> void func2(A&& t) {
func3(t);
func4(std::forward<A>(t);
}
template <typename B> void func3(B&&) { }
template <typename C> void func4(C&&) { }
int foo;
const int bar;
func1(foo); // ERROR
func1(bar); // ERROR
func1(std::move(foo)); // OK
func2(foo); // OK, A = int&, B = int&, C = int&
func2(bar); // OK, A = const int&, B = const int&, C = const int&
func2(std::move(foo)); // OK, A = int&&, B = int&, C = int&& <- note how && collapses to & without std::forward
You're defining the special member functions incorrectly, copy/move constructor is not defined in terms of class members, it defined in terms of the class.
instead of
class_name(const member_1&, ..., const member_n&)
class_name(const member_1&&, ..., const member_n&&)
you have to define your copy/move constructor as:
class_name(const class_name&) // copy-constructor
class_name(class_name&&) // move constructor
and inside it, use copy/move semantic. see c++draft class.copy
Related
I'm trying to convert a parameter pack into references, because some arguments to my function can be a mix of r-/l- values.
The function in question:
//must return tuple
template <typename ...U>
std::tuple<U...> input(const char* format, U ...args) {
std::tuple<U...> t = std::tuple<U...> (args...);
//other code....
}
There is some test code that I can't touch...
This will call my function:
template <typename... U>
std::tuple<U...> test_input(const char* fmt, U &&...inp) {
input(fmt, std::forward<U>(params)...);
//other stuff...
}
And 2 test objects (also untouchable) which have deleted copy/move constructors A() and B(). as in:
A(const A &) = delete; //same for B
A &operator=(const A &) = delete; //same for B
If I call the function, as is, I'll get "deleted copy-constructor" or "deleted constructor" errors. For example:
test_input("blah blah", 1, i, "a", std::string("a"), A(123) B("string"));
The problem is that it can be any mix of r-/l-values and I don't know how to convert them to all be references
I understand that I need a reference to the arguments. I've tried using std::forward, std::forward_as_tuple, std::make_tuple, as well as changing the second parameter to input to be U & ...args and U &&...args
I also understand that I need to use reference collapsing:
A& & becomes A&
A& && becomes A&
A&& & becomes A&
A&& && becomes A&&
I tried to use the first and third rules to convert anything to a type of A&, but I still get errors such as: call to deleted constructor of 'B' and expects an l-value for 2nd argument
In case my question wasn't clear - How do I convert args, the second argument of input, to a tuple of references?
I think you want to do something like this:
#include <tuple>
#include <string>
//must return tuple
template <typename ...U>
std::tuple<U&&...> input(const char*, U&&...args) {
return std::tuple<U&&...>(std::forward<U>(args)...);
//other code....
}
template <typename... U>
std::tuple<U&&...> test_input(const char* fmt, U &&...inp) {
return input(fmt, std::forward<U>(inp)...);
//other stuff...
}
struct A {
A(int) { }
A(const A &) = delete; //same for B
A &operator=(const A &) = delete; //same for B
};
struct B {
B(const char *) { }
B(const B &) = delete; //same for B
B &operator=(const B &) = delete; //same for B
};
int main() {
int i = 1;
test_input("blah blah", 1, i, "a", std::string("a"), A(123), B("string"));
}
[live demo]
This is a follow-up of Explicit ref-qualified conversion operator templates in action. I have experimented with many different options and I am giving some results here in an attempt to see if there is any solution eventually.
Say a class (e.g. any) needs to provide conversion to any possible type in a convenient, safe (no surprises) way that preserves move semantics. I can think of four different ways.
struct A
{
// explicit conversion operators (nice, safe?)
template<typename T> explicit operator T&& () &&;
template<typename T> explicit operator T& () &;
template<typename T> explicit operator const T& () const&;
// explicit member function (ugly, safe)
template<typename T> T&& cast() &&;
template<typename T> T& cast() &;
template<typename T> const T& cast() const&;
};
// explicit non-member function (ugly, safe)
template<typename T> T&& cast(A&&);
template<typename T> T& cast(A&);
template<typename T> const T& cast(const A&);
struct B
{
// implicit conversion operators (nice, dangerous)
template<typename T> operator T&& () &&;
template<typename T> operator T& () &;
template<typename T> operator const T& () const&;
};
The most problematic cases are to initialize an object or an rvalue reference to an object, given a temporary or an rvalue reference. Function calls work in all cases (I think) but I find them too verbose:
A a;
B b;
struct C {};
C member_move = std::move(a).cast<C>(); // U1. (ugly) OK
C member_temp = A{}.cast<C>(); // (same)
C non_member_move(cast<C>(std::move(a))); // U2. (ugly) OK
C non_member_temp(cast<C>(A{})); // (same)
So, I next experiment with conversion operators:
C direct_move_expl(std::move(a)); // 1. call to constructor of C ambiguous
C direct_temp_expl(A{}); // (same)
C direct_move_impl(std::move(b)); // 2. call to constructor of C ambiguous
C direct_temp_impl(B{}); // (same)
C copy_move_expl = std::move(a); // 3. no viable conversion from A to C
C copy_temp_expl = A{}; // (same)
C copy_move_impl = std::move(b); // 4. OK
C copy_temp_impl = B{}; // (same)
It appears that the const& overload is callable on an rvalue, which gives ambiguities, leaving copy-initialization with an implicit conversion as the only option.
However, consider the following less trivial class:
template<typename T>
struct flexi
{
static constexpr bool all() { return true; }
template<typename A, typename... B>
static constexpr bool all(A a, B... b) { return a && all(b...); }
template<typename... A>
using convert_only = typename std::enable_if<
all(std::is_convertible<A, T>{}...),
int>::type;
template<typename... A>
using explicit_only = typename std::enable_if<
!all(std::is_convertible<A, T>{}...) &&
all(std::is_constructible<T, A>{}...),
int>::type;
template<typename... A, convert_only<A...> = 0>
flexi(A&&...);
template<typename... A, explicit_only<A...> = 0>
explicit flexi(A&&...);
};
using D = flexi<int>;
which provides generic implicit or explicit constructors depending on whether the input arguments can be implicitly or explicitly converted to a certain type. Such logic is not that exotic, e.g. some implementation of std::tuple can be like that. Now, initializing a D gives
D direct_move_expl_flexi(std::move(a)); // F1. call to constructor of D ambiguous
D direct_temp_expl_flexi(A{}); // (same)
D direct_move_impl_flexi(std::move(b)); // F2. OK
D direct_temp_impl_flexi(B{}); // (same)
D copy_move_expl_flexi = std::move(a); // F3. no viable conversion from A to D
D copy_temp_expl_flexi = A{}; // (same)
D copy_move_impl_flexi = std::move(b); // F4. conversion from B to D ambiguous
D copy_temp_impl_flexi = B{}; // (same)
For different reasons, the only available option direct-initialization with an implicit conversion. However, this is exactly where implicit conversion is dangerous. b might actually contain a D, which may be a kind of container, yet the working combination is invoking D's constructor as an exact match, where b behaves like a fake element of the container, causing a runtime error or disaster.
Finally, let's try to initialize an rvalue reference:
D&& ref_direct_move_expl_flexi(std::move(a)); // R1. OK
D&& ref_direct_temp_expl_flexi(A{}); // (same)
D&& ref_direct_move_impl_flexi(std::move(b)); // R2. initialization of D&& from B ambiguous
D&& ref_direct_temp_impl_flexi(B{}); // (same)
D&& ref_copy_move_expl_flexi(std::move(a)); // R3. OK
D&& ref_copy_temp_expl_flexi(A{}); // (same)
D&& ref_copy_move_impl_flexi = std::move(b); // R4. initialization of D&& from B ambiguous
D&& ref_copy_temp_impl_flexi = B{}; // (same)
It appears that every use case has its own requirements and there is no combination that might work in all cases.
What's worse, all above results are with clang 3.3; other compilers and versions give slightly different results, again with no universal solution. For instance: live example.
So: is there any chance something might work as desired or should I give up conversion operators and stick with explicit function calls?
The C++ standard unfortunately does not have any special rule to resolve this particular ambiguity. The problem come from the fact that you are trying to overload on 2 different things: the type that the compiler is trying to convert to; and the kind of reference from which you are trying to convert from.
By introducing proxy classes, you can split the resolution in 2 steps. Step 1: decide if it's an r-value reference, an l-value reference, or a const l-value reference. Step 2: convert to any type, keeping the decision made in step 1 about the kind of reference. That way, you can use your solution with a cast() function but save you from having to specify the type:
struct A
{
class A_r_ref
{
A* a_;
public:
A_r_ref(A* a) : a_(a) {}
template <typename T> operator T&&() const&&;
};
struct A_ref
{
A* a_;
public:
A_ref(A* a) : a_(a) {}
template <typename T> operator T&() const&&;
};
struct A_const_ref
{
const A* a_;
public:
A_const_ref(const A* a) : a_(a) {}
template <typename T> operator const T&() const&&;
};
A_r_ref cast() && { return A_r_ref(this); }
A_ref cast() & { return A_ref(this); }
A_const_ref cast() const& { return A_const_ref(this); }
};
Consider the following code:
#include <boost/range.hpp>
#include <boost/iterator/counting_iterator.hpp>
typedef boost::iterator_range<boost::counting_iterator<int>> int_range;
template <typename T>
class Ref {
T* p_;
public:
Ref(T* p) : p_(p) { }
/* possibly other implicit conversion constructors,
but no unconstrained template constructors that don't
use the explicit keyword... */
operator T*() const { return p_; }
operator const T*() const { return p_; }
};
struct Bar { };
class Foo {
public:
Foo(int a, char b) { /* ... */ }
Foo(int a, const Ref<Bar>& b) { /* ... */ }
Foo(int a, const int_range& r) { /* ... */ }
};
int main() {
Bar b;
Foo f(5, &b);
return 0;
}
This code doesn't compile because the use of the Foo constructor is ambiguous, since boost::iterator_range apparently has a templated constructor that takes a single argument and is not declared as explicit. Assuming that changing the structure of Ref is not an option, how can I fix this problem? I came up with the following possible solution, but it's ugly and not easily maintainable, especially if there are more than a few constructors of Foo:
template<typename range_like>
Foo(
int a,
const range_like& r,
typename std::enable_if<
not std::is_convertible<range_like, Ref<Bar>>::value
and std::is_convertible<range_like, int_range>::value,
bool
>::type unused = false
) { /* ... */ }
or similarly
template<typename range_like>
Foo(
int a,
const range_like& r,
typename std::enable_if<
std::is_same<typename std::decay<range_like>::type, int_range>::value,
bool
>::type unused = false
) { /* ... */ }
which has the disadvantage that all other implicit type conversion for int_range is disabled, and thus relies on unspecified features of boost (and my instincts tell me it's probably a bad idea anyway). Is there a better way to do this? (C++14 "concepts-lite" aside, which is really what this problem wants I think).
I think this program is a minimal example of your problem:
#include <iostream>
struct T {};
struct A {
A(T) {}
};
struct B {
B(T) {}
};
struct C {
C(A const&) { std::cout << "C(A)\n"; }
C(B const&) { std::cout << "C(B)\n"; }
};
int main() {
C c{T{}};
}
You have two types A and B both implicitly convertible from another type T, and another type C implicitly convertible from A and B, but for which implicit conversion from T is ambiguous. You desire to disambiguate the situation so that C is implicitly convertible from T using the sequence of conversions T => A => C, but you must do so without changing the definitions of A and B.
The obvious solution - already suggested in the comments - is to introduce a third converting constructor for C: C(T value) : C(A(value)) {}. You have rejected this solution as not general enough, but without clarifying what the "general" problem is.
I conjecture that the more general problem you want solved is to make C unambiguously implicitly convertible from any type U that is implicitly convertible to A using the sequence of conversions U => A => C. This is achievable by introducing an additional template constructor to C (Live code demo at Coliru):
template <typename U, typename=typename std::enable_if<
!std::is_base_of<A,typename std::decay<U>::type>::value &&
std::is_convertible<U&&, A>::value>::type>
C(U&& u) : C(A{std::forward<U>(u)}) {}
The template constructor is a direct match for C(U), and so is unambiguously preferred over the C(A) and C(B) constructors that would require a conversion. It is constrained to accept only types U such that
U is convertible to A (for obvious reasons)
U is not A or a reference to A or a type derived from A, to avoid ambiguity with the C(const A&) constructor and infinite recursion in the case that U is e.g. A& or A&&.
Notably this solution does not require changing the definitions of T, A, B, C(A const&) or C(B const&), so it is nicely self-contained.
We are trying to refactor our code and one of the improvements we want is the following: many functions have many arguments but many of them share a common subset. So, we would like to create a structure that would group them. The problem is that some functions need some of the parameters to be const and some not. Some of these functions must be able to call a subset of these functions supplying this parameter-grouping structure, but under the following restriction: a called function cannot "degrade" the constness of this structure (see the following example). Implementing all required variations of this struct solves the problem but not elegantly. One solution we're working on is to use templates, e.g:
template<class A, class B, class C>
struct my_container
{
A a;
B b;
C c;
};
void foo1(my_container<int, char, float const> & my_cont)
{
}
void foo2(my_container<int const, char, float const> & my_cont)
{
// This should NOT be allowed: we do mind something being const to be treated by the
// called function as non-const.
foo1(my_cont);
}
void foo3(my_container<int, char, float> & my_cont)
{
// This should be allowed: we don't mind something being non-const to be treated by the
// called function as const.
foo2(my_cont);
}
Our problem is that foo2 calls foo1 without the compiler complaining, and we'd like the exact opposite. Is this even possible to implement with templates? Is there any other technique?
Neither should work. Different instantiations of a template are
unreleated types, with no implicit conversions between them. So
my_container<int, char, float const>, my_container<int const, char,
float const> and my_container<int, char, float> are all unrelated
types, with no implicit conversions between them.
It should be possible to work out something using inheritance, using
metaprogramming tricks to determine what you inherit from, but I'm not
sure how, and I suspect that it would be more effort than it's worth.
Without bordering on undefined behavior, this can be achieved with another level of indirection. Add a view class which references the original members. Constness can be added implicitly, but cannot be removed.
template<class A, class B, class C>
struct my_container
{
A a;
B b;
C c;
};
template <class A, class B, class C>
class my_container_view
{
A* a_;
B* b_;
C* c_;
public:
template <class A_, class B_, class C_>
my_container_view(my_container<A_, B_, C_>& source):
a_(&source.a), b_(&source.b), c_(&source.c)
{}
template <class A_, class B_, class C_>
my_container_view(my_container_view<A_, B_, C_>& source):
a_(&source.a()), b_(&source.b()), c_(&source.c())
{}
A& a() const { return *a_; }
B& b() const { return *b_; }
C& c() const { return *c_; }
};
void foo1(my_container_view<int, char, float const> my_cont)
{
my_cont.a() = 10;
my_cont.b() = 'a';
my_cont.c() /*= 3.14*/;
}
void foo2(my_container_view<int const, char, float const> my_cont)
{
my_cont.a() /*= 10*/;
my_cont.b() = 'a';
my_cont.c() /*= 3.14*/;
//foo1(my_cont); //not allowed
}
void foo3(my_container_view<int, char, float> my_cont)
{
my_cont.a() = 10;
my_cont.b() = 'a';
my_cont.c() = 3.14;
t
foo2(my_cont);
}
int main()
{
my_container<int, char, float> mc;
foo1(mc);
foo2(mc);
foo3(mc);
}
(I have my doubts, though, how much this is worth. Normally with classes, either you can modify all its members - and you just don't modify the ones you don't want to -, or you can't modify any. If you want this level of control, you'd rather pass each argument separately - the opposite of what you are doing.)
My solution with a bit meta-programming. Looks pretty ugly and not throughoutly tested, but anyways:
This way, everything should work in general "out of the box"
#include <iostream>
#include <boost/type_traits.hpp>
template<class A, class B, class C>
struct my_container
{
A a;
B b;
C c;
template<typename An, typename Bn, typename Cn>
operator my_container<An,Bn,Cn>& ()
{
/* First, check whether compatible at all */
BOOST_STATIC_ASSERT((boost::is_same<typename boost::remove_cv<A>::type, typename boost::remove_cv<An>::type>::value));
BOOST_STATIC_ASSERT((boost::is_same<typename boost::remove_cv<B>::type, typename boost::remove_cv<Bn>::type>::value));
BOOST_STATIC_ASSERT((boost::is_same<typename boost::remove_cv<C>::type, typename boost::remove_cv<Cn>::type>::value));
/* Enforce const'ness */
BOOST_STATIC_ASSERT( !boost::is_const<A>::value || boost::is_const<An>::value );
BOOST_STATIC_ASSERT( !boost::is_const<B>::value || boost::is_const<Bn>::value );
BOOST_STATIC_ASSERT( !boost::is_const<C>::value || boost::is_const<Cn>::value );
return *reinterpret_cast< my_container<An,Bn,Cn>* >(this);
}
};
void foo1(my_container<int, char, float const> & my_cont)
{
}
void foo2(my_container<int const, char, float const> & my_cont)
{
// This should NOT be allowed: we do mind something being const to be treated by the
// called function as non-const.
//foo1(my_cont); /// BOOST_STATIC_ASSERT fails! Hurray!
}
void foo3(my_container<int, char, float> & my_cont)
{
// This should be allowed: we don't mind something being non-const to be treated by the
// called function as const.
foo2(my_cont); /// No complaints! Hurray!
}
int main(int argc, char* argv[])
{
my_container<int,char,float> foobar;
foo3(foobar);
return 0;
}
I have a class A:
template <typename T, int I> struct A {};
and a class B. I would like object's of type B to implicitly convert to A when given as function arguments. B looks like this:
template <typename T>
struct B {
operator A<T,0> &() const { return *new A<T,0>(); }
};
However, my test (below) fails with GCC 4.5, giving the error: no matching function for call to 'test(B&)' Where am I going wrong here? Do other compilers also reject this?
template <typename T, int I>
void test(A<T,I> &a) { delete &a; }
int main(int argc, char *argv[])
{
B<int> b;
test(b);
return 0;
}
p.s. I've now put my own solution in an answer below.
Unrelated to your problem but return *new A<T,0>(); is wrong since it leaks memoryinvites a memory leak. You should not use new here. return A<T, 0>(); and removing the reference from the return type works just fine and does not leak memory.
If you want an implicit conversion from B to A you would need either:
A cast operator on B:
operator A<T,0>();
or an A constructor which takes a B reference:
A( const B& other );
or for B to derive from A. What you have declared:
operator A<T,0> &() const;
looks a bit like an ill-declared address-of overload.
However, since test() takes a reference (and non-const at that), the casting operator option won't work.
This is what I've tested:
template <typename T, int I> struct A {};
template <typename T>
struct B {
//operator A<T,0> &() const { return *new A<T,0>(); }
template< int I >
operator A<T, I> () const { return A< T, 0 >(); }
};
template <typename T, int I>
void test(A<T,I> &) { }
int f()
{
B<int> b;
A<int, 0> a( b );
test(a); // <-- Success
test(b); // <-- Failure, "could not deduce template argument"
return 0;
}
Conversion to A by initialising a local variable works fine.
Are you sure you actually want such an implicit conversion here? It sounds like a perfect way to confuse yourself or another maintainer, or worse, call a function using the wrong argument because the implicit conversion allows it. Instead, consider a make_A template like std::make_pair to explicitly show your intention at the call site.
Providing an overload of test like the following will enable to write
test(b) as in the question.
For example:
template <typename T>
void test(B<T> const &b) {
test( static_cast< A<T,0>& >( b ) );
}
test(b); // caller
If such overload isn't allowed but you are allowed to modify B's
definition, how about providing member function which returns A
like the following, instead of conversion function?
template <typename T>
struct B {
A<T,0> &to_A() const { return *new A<T,0>(); }
};
test( b.to_A() );
If you aren't allowed to modify B's definition, the above to_A will be
a free function like the following instead of member function:
template <typename T>
A<T,0> &to_A(B<T> const &b) {
return static_cast< A<T,0>& >( b );
}
test( to_A( b ) );
Hope this helps
This fails in VC++ too. To make it work, add this method:
template <typename T>
void test(B<T> &b)
{
test( static_cast< A<T,0>& > (b) );
}
This will take an actual B, explicitly do the conversion (via static_cast), and then call test using the A we just made.
I get errors when I run it though. I hope this is just example code, and you're not doing delete &a in your actual code. RobH gave a better conversion operator for you, and avoids the pointer messiness.
I've settled on using the pass by value conversion operator suggested by Konrad; the explicit template function call of Let_Me_Be; and I sprinkled a little bit of C++0x magic on top: an rvalue reference on the parameter to test. (Or, should that be C++ 2011 now?)
template <typename T, int I> struct A { int x; };
template <typename T>
struct B {
operator A<T,0> () const { return A<T,0>(); }
};
template <typename T, int I>
void test(A<T,I> &&a) { a.x=7; printf("%d\n", x); }
int main(int argc, char *argv[])
{
B<int> b;
test<int,0>(b);
return 0;
}