You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何编译器报错A c{}.foo()?如何避免赋值操作?

class A {
public:
    A(void) = default;

    A& foo(void)
    {
        return *this;
    }
};

int main(int, char**)
{
    A a = A{}.foo();
    A b{};
    A c{}.foo();

    return 0;
}

编译错误输出:

C:\temp\cpp>clang test.cpp
test.cpp:15:8: error: expected ';' at end of declaration
   15 |   A c{}.foo();
      |        ^
      |        ;
1 error generated.

问题解答

1. 编译器为何会对语句A c{}.foo()报错?

这是C语法规则的限制:A c{}本身是一条变量声明语句,用来创建名为c的A类型对象并完成初始化。但在声明语句的初始化器后直接追加.foo()调用的写法,不符合C的声明语法规范——编译器会认为A c{}已经是完整的声明,后续的.foo()属于多余的非法语法,因此要求在{}后加分号来终止声明语句。

简单来说:C++不允许将变量声明和成员函数调用链式写在一起,这种写法混淆了声明语句和表达式语句的语法边界。

2. 是否存在可以避免使用赋值操作的实现方式?

存在,且能适配禁用拷贝构造函数的场景,以下是几种可行方案:

  • 方案1:利用右值引用转移临时对象所有权(C++11及以上)
    如果类A允许移动构造(默认生成或显式声明),可以通过std::move将临时对象的所有权转移给目标变量,完全避免拷贝操作:

    class A {
    public:
        A(void) = default;
        A(const A&) = delete; // 禁用拷贝构造
        A(A&&) = default;     // 启用移动构造
    
        A& foo(void) { return *this; }
    };
    
    int main() {
        A c = std::move(A{}.foo()); // 通过move转移临时对象,无拷贝
        return 0;
    }
    
  • 方案2:静态工厂函数+C++17 NRVO优化
    给类A添加静态工厂函数,在函数内部完成对象初始化和foo()调用,C++17的NRVO(命名返回值优化)会直接在目标变量的内存空间构造对象,无需拷贝或移动:

    class A {
    public:
        A(void) = default;
        A(const A&) = delete;
        A(A&&) = default;
    
        A& foo(void) { return *this; }
    
        static A create_and_foo() {
            A a;
            a.foo();
            return a;
        }
    };
    
    int main() {
        A c = A::create_and_foo(); // C++17及以上无拷贝/移动操作
        return 0;
    }
    
  • 方案3:lambda表达式直接初始化
    用lambda表达式封装对象创建和函数调用的逻辑,返回右值对象初始化变量,同样无需拷贝:

    int main() {
        A c([]{ 
            A a; 
            a.foo(); 
            return std::move(a); 
        }());
        return 0;
    }
    

内容的提问来源于stack exchange,提问作者albert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 20:30:33