C++标准明确规定:在函数声明中使用默认参数时,默认参数表达式所涉及的类型必须是完整类型。这里的Bar bar = {}里,初始化表达式{}需要依赖Bar的完整定义——编译器得知道它的大小、是否有默认构造函数等信息,才能生成合法的默认对象。而在Foo模板的baz函数声明处,Bar只是前向声明,属于不完整类型,所以Clang的报错是严格遵循标准的行为。
你觉得标准的限制让人困惑,但从语言设计逻辑来看,这种要求是为了保证编译器在处理函数声明阶段就能明确默认参数的合法性,避免后续类型定义变化带来的潜在问题。比如如果Bar的完整定义里没有默认构造函数,那之前的Bar bar = {}就会变成非法代码,延迟检查可能会把这种错误隐藏到模板实例化阶段,增加调试的复杂度。