【问题标题】:Is there a way to disable auto declaration for non regular types?有没有办法禁用非常规类型的自动声明?
【发布时间】:2016-11-30 12:16:39
【问题描述】:

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

Implicit Evaluation of “auto” Variables and Arguments 由 Joel Falcou 和其他人撰写。

隐式评估应:

  1. 使类实现者能够指示此类的对象在 auto 语句中进行评估;
  2. 使他们能够确定评估对象的类型;

...


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

但是在我看来,如果一个类型是Not Regular(例如,参见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&lt;bool&gt;::reference(也是一个引用包装器)的核心。禁用(以某种方式)语法 auto b = v[10] 不会解决 std::vector&lt;bool&gt; 的问题,但它会使错误的使用更加困难。

我错过了什么吗?我应该改变设计的其他部分吗?非常规类是否应具有有助于编译器确定更通用自动的类型特征(例如,将 bool 推导出为 auto b = v[10] 其中 std::vector&lt;bool&gt; v。)

【问题讨论】:

  • 是否添加了static_assert 来分配可能性?
  • @wasthishelpful,赋值不是问题,我可以在operator=中实现我需要的语义,甚至可以删除。问题是允许这种auto r = rd 语法,并允许它具有错误的含义(在 C++ 中似乎不可能更改)。 auto r = rd 这行不是赋值,而是带有(错误的)类型推导的构造。 (更具体地说,对于“类引用类型”,它是(或应该是)绑定操作)。
  • 根据cplusplus.com/reference/functional/reference_wrapper,您可以通过调用ref.get() 访问您的值。从中构建应该是明确的。
  • 是的,如果 C++ 有一些特性可以避免在涉及类型时让你自爆,那不是很好吗?但是,如果我们愿意,在我的列表中禁用有符号和无符号类型之间的隐式转换的能力会更高......
  • 不,无法禁用此核心语言功能。直到有人编写了一个连贯的提案并完成了将其合并到下一个 C++ 标准中所需的所有工作。 auto 被定义为做一件非常具体的事情,而这件事情和模板参数推导中发生的事情完全一样。如果您建议在某些情况下禁用 auto,您可能还应该在相同情况下禁用模板参数推导,以保持一致性。

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


【解决方案1】:

复制构造函数意味着您希望类被复制。 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

【讨论】:

  • 好吧,我不同意,copy-constructible 应该意味着至少这是有效的decltype(y) x = y 是有效的并且有一些意义。 auto x = y 在语义上是不同的,因为在通用代码中人们期望 x 具有值语义,即使 y 没有。我只是说auto 显然过于严格。遗憾的是,对于真正的通用代码,需要执行类似typename value_rep_of&lt;decltype(y)&gt;::type x = y; 的操作。其中value_rep 是一个特征(对于大多数情况来说微不足道,非常规类型除外)。
  • @alfc 如果您接受包装器,C++17 中的模板构造函数类型推导可能会有所帮助。所以value a=b; 其中value&lt;T&gt; 是一个模板,它在其自身的字段中存储一个值。
  • 好点,我必须调查一下。这是非常有前途的,因为它隐藏/抽象了你的 hack。
  • 事实证明,对于 C++14,我找到的解决方案是禁用移动和复制构造函数,这很有意义并迫使我使用 auto&amp;&amp; 而不是 auto 但是没关系,因为最多一个没有复制或移动构造函数的类基本上是一个类似引用的类型。然而,技术在 C++17 中停止工作。所以我问了这个后续问题stackoverflow.com/questions/58469786/…
猜你喜欢
  • 1970-01-01
  • 2018-02-23
  • 1970-01-01
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多