有没有办法禁用非常规类型的自动声明?

时间:2016-11-30 12:16:40

标签: c++ c++11 auto regular-type

更新:有人建议在某些情况下更改auto的含义。

  

Implicit Evaluation of “auto” Variables and Arguments来自Joel Falcou和其他人。

     

隐式评估应:

     
      
  1. 启用类实现者以指示在auto语句中评估此类的对象;
  2.   
  3. 启用它们以确定已评估对象的类型;
  4.         

    ...

C ++ 11的auto关键字很棒。

但是,在我看来,如果某个类型是非常规(例如,参见What is a "Regular Type" in the context of move semantics?),则auto的使用会变得棘手。

有没有办法禁用此类型的auto声明?

假设有一个模拟引用的ref

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>`.

(在现实生活中,这将是一个更复杂的课程,重点是手头的课程不规律。)

我发现auto r = rd无法工作(给出编译错误)的唯一方法是使类不可复制,但是我需要类具有复制构造函数(具有特殊语义,但仍然是复制构造函数) )。

有没有办法以某种方式禁用语法auto r = rd?当decltype(rd)不规律时。

(更好的方法是能够以某种方式告诉编译器auto应该做什么。)

注意:这不是一个非常人为的问题,可以看出这类问题是std::vector<bool>::reference(它也是一个参考包装器)的核心。禁用(某种程度上)语法auto b = v[10]不会解决std::vector<bool>的问题,但会更难以使用。

我错过了什么吗?我应该改变设计的其他部分吗?非常规类是否具有可帮助编译器确定更一般的自动的类型特征(例如,对bool auto b = v[10] std::vector<bool> v进行推导notifyDataSetChanged()。)

1 个答案:

答案 0 :(得分:3)

复制构造函数意味着您希望复制该类。 auto x = y;会将y复制到x

如果您想要一个不想自动运行的超级特殊副本,可以使用代理对象。

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;
};

现在我们可以:

strange foo() { return pseudo(strange{}); }

strange x = pseudo(foo());

现在,每次复制strange 的尝试都必须通过调用pseudo,使用auto从来都不合法,因为没有副本构造

您也可以将复制构造函数设为私有,并使用它来实现pseudo复制构造函数。

请注意,复制/移动ctor的含义受C ++中的省略规则约束。

在C ++ 17模板类中,类型推导可以:

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 );

a.v将是int