Is there a way to disable auto declaration for non

2019-02-16 14:57发布

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:

  1. Enable class implementers to indicate that objects of this class are evaluated in an auto statement;
  2. 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.)

1条回答
Luminary・发光体
2楼-- · 2019-02-16 15:48

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.

查看更多
登录 后发表回答