C++ 中 `operator auto() = delete` 的目的是什么?

What is the purpose of `operator auto() = delete` in C++?

C++中的一个class可以定义一个或多个转换运算符。其中一些可以自动推导结果类型:operator auto。所有编译器都允许程序员将任何运算符标记为已删除,operator auto 也是如此。对于具体类型,删除意味着尝试调用此类转换将导致编译错误。但是 operator auto() = delete 的目的是什么?

考虑一个例子:

struct A {
    operator auto() = delete;
};

struct B : A { 
    operator auto() { return 1; }
};

int main() {
    B b;
    A a = b;   // error in Clang
    int i = b; // error in Clang and GCC
    int j = a; // error in Clang and GCC and MSVC
}

由于编译器无法推导结果类型,它实际上禁止从此 class 或派生的 classes 进行任何转换,错误为:

function 'operator auto' with deduced return type cannot be used before it is defined.

演示:https://gcc.godbolt.org/z/zz77M5zsx

旁注,编译器在仍然允许哪些转换方面略有不同(例如,GCC 和 MSVC 允许转换为基 class),其中哪一个就在这里?

But what could be the purpose of operator auto() = delete?

以下函数的用途是什么?

auto f() = delete;

根据语法函数,[dcl.fct.def.general]/1函数定义函数体可能是= delete;例如,将函数定义为已删除在语法上是有效的。

C++14 为函数引入了 auto return 类型推导,并给出了函数定义允许的语法,根据 C++14,语法允许使用 auto return类型.

这种极端情况是否有用并不是语言真正考虑的问题,因为引入极端情况总是要付出代价的(例如,“函数定义的语法应该有一个特例 auto 类型推导").虽然在何处可以提供明确默认的函数定义方面存在限制 ([dcl.fct.def.default]), the same restrictions do not apply for explicitly-deleted function definitions ([dcl.fct.def.delete])。


which one of them is right here?

A a = b;   // error in Clang

Clang 为这个初始化选择用户定义的转换函数是有争议的错误。根据 [dcl.init.general]/15.6, /15.6.2:

Otherwise, if the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, constructors are considered. [...]

优先于/15.6.3

Otherwise (i.e., for the remaining copy-initialization cases), user-defined conversions that can convert from the source type to the destination type or (when a conversion function is used) to a derived class thereof are enumerated as described in [over.match.copy], and the best one is chosen through overload resolution ([over.match]). [...]


作为该语言的用户,提供 auto return 类型的函数的已删除定义 可以 用于语义标记没有人应该提供给定函数名称的任何类型的重载。

auto f() = delete;  // never expose a valid overload for f()

// elsewhere:
int f() { return 42; }
  // error: functions that differ only in 
  //        their return type cannot be overloaded

对于用户定义转换运算符的特殊情况,可以使用显式默认 auto return 类型的用户定义转换函数,例如在预期的组合基础 class 中,类似于 Scott Meyers C++03 使 class 不可复制的技巧(在 C++11 引入 = delete 之前)。

struct NoUserDefinedConversionFunctionsAllowed {
    operator auto() = delete;
};

struct S : NoUserDefinedConversionFunctionsAllowed { 
    operator int() { return 1; }  // can never be used
};