带auto参数的Lambda导致非const成员函数匹配错误,求解决方案
问题分析
带auto&参数的Lambda的operator()是模板函数,在Concept检查阶段,编译器仅验证函数调用的签名是否匹配(即能否推导出模板参数使调用合法),不会实例化Lambda函数体。因此ValidConstSignature<int, FunctionT>会被判定为满足(可推导出U=const int让签名匹配),但实例化时Lambda函数体内的abc++会因参数是const int&而报错。同时由于两个重载的Concept都满足,编译器错误地选择了const版本的getBar。
解决方案
将非const版本的getBar改为非const左值引用限定的成员函数,内部用constexpr if优先尝试非const参数传递,仅当不满足非const签名时才使用const参数传递。这样能确保非const对象优先选择非const的参数传递路径,避免编译器错误匹配const版本。
修改后的完整代码:
#include <concepts> template <class T, class FunctionT> concept ValidNonConstSignature = requires(FunctionT exec_fn, T& value) { exec_fn(value); }; template <class T, class FunctionT> concept ValidConstSignature = requires(FunctionT exec_fn, const T& value) { exec_fn(value); }; class Foo { public: // 非const左值对象专属版本 template <class FunctionT> auto getBar(FunctionT callback) & { if constexpr (ValidNonConstSignature<int, FunctionT>) { return callback(m_abc); } else if constexpr (ValidConstSignature<int, FunctionT>) { return callback(static_cast<const int&>(m_abc)); } else { static_assert(false, "Callback does not match valid signatures"); } } // const对象专属版本 template <class FunctionT> requires ValidConstSignature<int, FunctionT> auto getBar(FunctionT callback) const& { return callback(m_abc); } private: int m_abc {}; }; int main() { Foo foo; foo.getBar([](int& abc){ return abc++; }); // 正常编译 foo.getBar([](const int& abc){ return abc++; }); // 正确报错:increment of read-only reference ‘abc’ foo.getBar([](auto& abc){ return abc++; }); // 正常编译,使用非const参数传递 foo.getBar([](const auto& abc){ return abc++; }); // 正确报错:increment of read-only reference ‘abc’ const Foo cfoo; cfoo.getBar([](const int& abc){ return abc; }); // 正常编译 // cfoo.getBar([](int& abc){ return abc++; }); // 正确报错:不满足ValidConstSignature约束 return 0; }
补充说明
若尝试通过让ValidConstSignature仅在ValidNonConstSignature不满足时生效的方式优化Concept,会导致const对象无法调用接受const参数的Lambda(因为ValidNonConstSignature可能因参数隐式转换而满足),因此不推荐这种方案。
内容的提问来源于stack exchange,提问作者FrogTheFrog
相关产品推荐
相关产品推荐

