UPDATE: There is a proposal to change the meaning of auto
in certain situations.
Implicit Evaluation of “auto” Variables and Arguments by Joel Falcou and others.
The implicit evaluation shall:
- Enable class implementers to indicate that objects of this class are evaluated in an auto statement;
- Enable them to determine the type of the evaluated object;
...
C++11's auto
keyword is great.
However in my opinion if a type is Not Regular (see for example, What is a "Regular Type" in the context of move semantics?) the usage of auto
becomes tricky.
Is there a way to disable the auto
declaration for such type?
Suppose one has a ref
class that emulates a reference
double 5.;
ref<double> rd = d; // `ref` behaves like a reference, so it is not a regular type
ref<double> rd2 = rd; // `ref` can be (syntactically) copy constructible, (it is not regular for other reason)
auto r = rd; // now r is not `double`, but EVEN WORST it is `ref<double>`.
(in real life it would be a more complicated class, the important point is that the class at hand it is not regular.)
The only way I found auto r = rd
not to work (give a compile error) is to make the class non copyable, however I need the class to have copy constructor (with a special semantics, but a copy constructor still).
Is there a way to disable a syntax auto r = rd
somehow? when decltype(rd)
is not regular.
(Even better could be to be able somehow to tell the compiler what auto
should do precisely).
Note: This is not a very artificial problem, one could see that this type of problem is at the core of std::vector<bool>::reference
(which is also a reference wrapper). Disabling (somehow) the syntax auto b = v[10]
wouldn't solve the problem of std::vector<bool>
but it will make bad usage harder.
Am I missing something? Should I change some other part of the design? Should the non-regular classes have a type trait that would help the compiler determine a more general auto (for example deduce bool
for auto b = v[10]
where std::vector<bool> v
.)
A copy constructor means you expect the class to be copied. auto x = y;
does a copy of y
into x
.
If you want a super-special copy that you don't want to be run automatically, you can use a proxy object.
template <class T>
struct pseudo_copy;
template <class T>
struct pseudo_copy<T const&> {
T const& t;
// T const& can be initialized from T&&:
pseudo_copy(T const& tin) :t(tin) {}
pseudo_copy(T&& tin): t(tin) {}
pseudo_copy(pseudo_copy const&) = delete;
};
template <class T>
struct pseudo_copy<T&&> {
T&& t;
pseudo_copy(T&& tin): t(std::move(tin)) {}
pseudo_copy(pseudo_copy const&) = delete;
};
template <class T>
pseudo_copy<T const&> pseudo(T& t) { return {t}; }
template <class T>
pseudo_copy<T&&> pseudo(T&& t) { return {t}; }
struct strange {
strange(strange const&)=delete;
strange(pseudo_copy<strange const&>) {} // copy ctor
strange(pseudo_copy<strange&&>) {} // move ctor
strange() = default;
};
Now we can:
strange foo() { return pseudo(strange{}); }
strange x = pseudo(foo());
and now every attempt to copy strange
must go through a call to pseudo
, and use of auto
is never legal, because nothing has a copy constructor.
You could also make the copy constructor private, and use it to implement the pseudo
copy constructor.
Note that the meaning of copy/move ctor is constrained by elision rules in C++.
In C++17 template class type deduction could make:
template <class T>
struct value{
value_type_of<T> v;
value(T in): v(std::forward<T>(in)) {}
};
int x = 3;
value a = std::ref( x );
And a.v
would be an int
.
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