小编Fed*_*dor的帖子

C++ 中“operator auto() = delete”的用途是什么?

C++ 中的类可以定义一个或多个转换运算符。其中一些可以自动推导结果类型: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
}
Run Code Online (Sandbox Code Playgroud)

由于编译器无法推断出结果类型,因此它实际上禁止从此类或派生类进行任何转换,并出现错误:

function 'operator auto' with deduced return type cannot be …
Run Code Online (Sandbox Code Playgroud)

c++ conversion-operator language-lawyer

27
推荐指数
1
解决办法
749
查看次数

`throw` 可以在 C++ 条件(三元)运算符中的逗号子表达式内吗?

众所周知,throw可以作为C++三元运算符的第二个或第三个操作数放置?:。但是它可以在操作数的逗号子表达式中吗?看起来编译器在这方面存在分歧。请考虑一个例子:

#include <iostream>

void foo(bool b) {
    int i = b ? 1 : (throw 0); //ok everywhere
    if ( !b )
        (std::cout << "smth\n", throw 0); //ok everywhere
    i = b ? 2 : (std::cout << "smth\n", throw 0); //ok in MSVC only
};
Run Code Online (Sandbox Code Playgroud)

这个例子被 MSVC 接受,但被 GCC 和 Clang 拒绝,演示:https : //gcc.godbolt.org/z/6q46j5exP

虽然错误信息:

#include <iostream>

void foo(bool b) {
    int i = b ? 1 : (throw 0); //ok everywhere
    if ( !b …
Run Code Online (Sandbox Code Playgroud)

c++ conditional-operator throw language-lawyer

23
推荐指数
2
解决办法
1062
查看次数

结构化绑定是否应作为 C++20 中的右值从函数返回?

考虑一个 C++20 程序,其中函数中foo有一个结构化绑定auto [y]。函数返回y,它被转换为对象类型AA可以从右值引用的常量引用构造。

#include <tuple>
#include <iostream>

struct A {
    A(const int &) { std::cout << "A(const int &) "; }
    A(int &&) { std::cout << "A(int &&) "; }
};

A foo() {
    auto [y] = std::make_tuple(1);
    return y;
}

int main() { foo(); }
Run Code Online (Sandbox Code Playgroud)

根据C++20语言标准应该选择哪一个构造函数?

Clang 选择A(const int &)和 GCC 选择A(int &&),演示:https : //gcc.godbolt.org/z/5q779vE6T

是否有一个编译器不支持这方面的标准?

c++ language-lawyer lvalue-to-rvalue c++20

23
推荐指数
1
解决办法
336
查看次数

可以在可变 lambda 中更改 `this` 吗?

大家都知道thisC++中的对象指针在其方法中是不能改变的。但是对于可变的 lambda,在何处this捕获,一些当前的编译器提供了这种可能性。考虑这个代码:

struct A {
    void foo() {
        //this = nullptr; //error everywhere

        (void) [p = this]() mutable { 
            p = nullptr; //#1: ok everywhere
            (void)p;
        };

        (void) [this]() mutable { 
            this = nullptr; //#2: ok in MSVC only
        };
    }
};

Run Code Online (Sandbox Code Playgroud)

在第一个 lambda 中this被捕获并赋予一个新名称p。这里所有的编译器都允许更改p. 在第二个 lambda 中this被自己的名字捕获,只有 MSVC 允许程序员改变它的值。演示:https : //gcc.godbolt.org/z/x5P81TT4r

我相信 MSVC 在第二种情况下行为不正确(尽管它看起来像一个不错的语言扩展)。谁能从标准中找到正确的措辞(搜索并不容易,因为该词this在那里被提及了 2800 多次)?

c++ lambda this language-lawyer

17
推荐指数
1
解决办法
616
查看次数

模板函数的原子约束中的替换失败需要子句

C++20 中的约束在通过将它们划分为原子约束来检查是否满足之前进行标准化。例如,约束E = E1 || E2有两个原子约束E1E2

原子约束中的替换失败应被视为原子约束的假值。

如果我们考虑一个示例程序,则会concept Complete = sizeof(T)>0检查正在定义的类T

template<class T>
concept Complete = sizeof(T)>0; 

template<class T, class U>
void f() requires(Complete<T> || Complete<U>) {}

template<class T, class U>
void g() requires(sizeof(T)>0 || sizeof(U)>0) {}

int main() { 
    f<void,int>(); //ok everywhere
    g<void,int>(); //error in Clang
}
Run Code Online (Sandbox Code Playgroud)

那么该函数f<void,int>()满足要求,因为由于替换失败而Complete<void>计算为,并且计算为。falseComplete<int>true

但相似的函数g<void,int>()会使编译器产生分歧。GCC 接受它,但 Clang 不接受:

error: no matching function for call to 'g'
note: …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer c++-concepts c++20

17
推荐指数
1
解决办法
794
查看次数

C++ 中具有相同参数类型和 require 子句的静态和非静态成员函数模板

参数类型相同的静态和非静态成员函数不能重载。但是,如果成员函数是模板并且其中之一有requires子句,那么所有编译器都允许它。但是当调用这两个成员函数时就会出现问题:

struct A {
    static int f(auto) { return 1; }
    int f(auto) requires true { return 2; }
};

int main() {
    [[maybe_unused]] int (A::*y)(int) = &A::f; // ok everywhere (if no below line)
    [[maybe_unused]] int (*x)(int) = &A::f; //ok in GCC and Clang (if no above line)
}
Run Code Online (Sandbox Code Playgroud)

如果只剩下一行(任意),main()则 GCC 和 Clang 接受该程序。但是当两行都main()存在时,Clang 会打印

error: definition with same mangled name '_ZN1A1fIiEEiT_' as another definition
Run Code Online (Sandbox Code Playgroud)

GCC 报告内部编译器错误。演示: https: //gcc.godbolt.org/z/4c1z7fWvx

所有编译器在接受struct …

c++ static overloading language-lawyer c++20

17
推荐指数
1
解决办法
428
查看次数

C++ 中的友元函数可以有一个默认参数,其类型有一个私有析构函数吗?

在下一个例子中,U带有私有析构函数的类有一个友元函数foo。这个友元函数的参数类型U为默认值U{}

class U{ ~U(); friend void foo(U); };
void foo(U = {});
Run Code Online (Sandbox Code Playgroud)

Clang 和 MSVC 接受此代码,但 GCC 拒绝它并显示错误

error: 'U::~U()' is private within this context
    2 | void foo(U = {});
      |                ^
Run Code Online (Sandbox Code Playgroud)

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

哪个编译器就在这里,友谊是否扩展到 C++ 中的默认参数?

c++ friend default-value language-lawyer

16
推荐指数
1
解决办法
319
查看次数

C++ 中仅返回类型不同的重载函数模板

众所周知,仅返回类型不同的普通函数不能在 C++ 中重载。

但这个限制不适用于重载的函数模板,例如:

int f(auto) { return 1; }
auto f(auto) { return 2; }
Run Code Online (Sandbox Code Playgroud)

所有编译器都接受它,演示: https: //gcc.godbolt.org/z/qj73Mzehd

为什么该语言对模板做出这样的例外?

如果重载函数的返回类型不同,则可以使用强制转换为预期函数类型来选择其中一个函数。令人惊讶的是,即使返回类型实际上相同,Clang 也允许解决歧义,例如:

((int(*)(int))f)(3);
Run Code Online (Sandbox Code Playgroud)

选择

int f(auto) { return 1; }
Run Code Online (Sandbox Code Playgroud)

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

Clang这里错了吗?

c++ templates language-lawyer overload-resolution c++20

16
推荐指数
1
解决办法
1209
查看次数

C++20 中的类定义之外可以默认比较运算符吗?

从C++20开始,编译器可以通过operator ==() = default语法的方式自动生成用户类的比较运算符。但是这个运算符必须只能在类定义内部默认吗?还是也可以在类定义之后?

考虑该程序:

struct A { friend bool operator==(A,A); };
bool operator==(A,A) = default;
Run Code Online (Sandbox Code Playgroud)

它被 GCC 接受,但被 Clang 拒绝,并出现错误:

error: equality comparison operator can only be defaulted in a class definition
Run Code Online (Sandbox Code Playgroud)

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

这里是哪个编译器?

例如,将运算符定义放在类定义之外对于仅将运算符放在一个翻译单元中非常有用,从而缩短了大程序的编译时间。

c++ comparison-operators language-lawyer c++20

15
推荐指数
1
解决办法
981
查看次数

C++ 中具有多个参数包的函数的重载解析

一个 C++ 函数可以有多个参数包。虽然看起来不太实用,但了解它们的语言规则仍然很有趣。

例如,如果有两个重载:

constexpr int f(auto...) { return 1; }
constexpr int f(auto..., auto...) { return 2; }
Run Code Online (Sandbox Code Playgroud)

f不带参数的调用f()在 MSVC 中选择版本 1,在 Clang 中选择版本 2,ambiguous overloaded call在 GCC 中选择版本 2。

如果f使用参数调用f(1),则 MSVC 和 GCC 都选择版本 1,而 Clang 仍选择版本 2。

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

这里是哪个编译器?

有一个类似的问题带有两个参数包的函数模板重载解析,但是

  • 那里的函数只有一个参数包作为函数参数(第二个参数包根本没有使用),
  • 该示例会导致所有测试的编译器中出现歧义错误(但是提到的编译器错误仍未解决)。实际上,在此示例中也可能出现歧义,但这里大多数编译器选择其中一个重载而不会出现错误。

c++ language-lawyer overload-resolution c++20 parameter-pack

15
推荐指数
1
解决办法
333
查看次数