为何C++20不支持`void f(Concept const auto&)`语法?
void f(Concept const auto&)这种函数声明语法? 这个问题的核心是C++20里带概念约束的auto参数有严格的语法规则——你把const的位置放错啦!
正确的语法逻辑
在C++20中,用概念约束auto参数时,语法结构是先指定概念,再指定带修饰的占位符类型:
Concept auto[cv限定/引用/指针]
这里的概念是用来约束auto推导出来的基础类型,而const、&、*这类修饰符必须放在auto的后面,而不是概念和auto之间。
举个直观的对比:
- ✅ 正确:
HasSize auto const& arg→ 先推导基础类型(比如std::string),确保它符合HasSize,再给这个类型加上const&修饰 - ❌ 错误:
HasSize const auto& arg→ 编译器会错误地把const auto当成HasSize的模板参数,引发语法解析失败
为什么你的代码会报错
看编译器给出的关键错误:
error: too few template arguments for concept 'HasSize'
这是因为当你写HasSize const auto&时,编译器会尝试把它解析为HasSize<const auto>——也就是试图给HasSize概念传递const auto作为模板参数,但const auto是个占位符,不是合法的类型实参,而HasSize需要一个明确的类型参数,所以编译器判定你“少传了模板参数”,进而引发后续的语法错误。
而你之前的f1到f5都是符合语法的,比如HasSize auto& arg、HasSize auto* arg,这些写法里的修饰符都在auto后面,编译器能正确识别:概念是约束auto推导的基础类型,修饰符是给这个基础类型加的额外限定。
修复你的代码
把f6的声明改成以下两种写法之一都可以:
写法一:调整const的位置(推荐)
这是最简洁符合标准的写法:
void f6(HasSize auto const& arg) {}
写法二:使用requires子句显式约束
如果你习惯把cv限定放在参数前面,也可以用requires子句单独约束参数的基础类型:
#include <type_traits> // 需要std::remove_cvref_t void f6(const auto& arg) requires HasSize<std::remove_cvref_t<decltype(arg)>> {}
这里std::remove_cvref_t用来去掉const&修饰,确保我们约束的是原始的std::string类型(不过C++概念对引用类型的约束会自动透传到底层类型,所以去掉也能正常工作,但加上会更清晰)。
内容的提问来源于stack exchange,提问作者xmllmx

