If we have a non-movable, non-copyable class with non-explicit constructor, we can return it and use as follows (in C++11):
#include <iostream>
class NonCop
{
public:
/*non explicit*/ NonCop(int a, int b) : number(a + b) {}
NonCop(const NonCop&) = delete;
int number;
};
NonCop get_non_cop()
{
return {1, 2};
}
int main()
{
NonCop &&nc = get_non_cop();
std::cout << "three: " << nc.number << std::endl;
return 0;
}
However if the constructor is explicit, it doesn't work. Is there any method of doing this in C++11/C++14 with no modifications in NonCop
?
Currently I'm using workaround with deriving from NonCop with wrapper that "deexplicits" the constructor but it doesn't seem very pretty.
No, this isn't possible. There is no mechanism to call explicit constructors while returning from a function in C++11 or 14 without having an implicit move or copy (that the compiler will certainly elide).
In C++17 you can just type return NonCop(1,2);
and due to "guaranteed elision" it will no longer require a move or copy constructor.
But this is C++, so yes, I can make your code work with zero additional overhead. By cheating, and returning a different type.
template<class T>
struct implicit_construct:T {
template<class...Ts>
implicit_construct(Ts&&...ts):
T(std::forward<Ts>(ts)...) // note: this is an EXPLICIT construction
{}
};
implicit_construct<NonCop> get_non_cop()
{
return {1, 2};
}
Live example.
An implicit_construct<NonCop>
derives from a NonCop
, so you can store the return value in a NonCop&&
.
If you are writing NonCop
yourself, then what I'd do is add:
struct explicit_construct_t {};
// ...
struct NonCop {
// ...
template<class...Ts>
NonCop( explicit_construct_t, Ts&&...ts ):
NonCop( std::forward<Ts>(ts)... )
{}
// ...
};
which means you can call explicit constructors by prefixing it with a explicit_construct_t
to call them implicitly:
NonCop get_non_cop() {
return {explicit_construct_t{}, 1, 2};
}
Unfortunatelly, in this context you can't return the temporary object, since in a return by value expression the compiler requires that the object's copy constructor is accessible, even if this object is going to be copy elided in the end. However, you could return a std::unique_ptr
instead of concrete object.
std::unique_ptr<NonCop> get_non_cop() {
return std::make_unique<NonCop>(1, 2);
}
Live Demo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With