如何在C++类内部用自身方法返回值定义类型别名?
问题描述
最初的代码实现如下:
struct LambdaWrapper { auto getLambda() { return []() { std::cout << "Lambda is called" << std::endl; }; } }; void useLambda(auto &&lambda) { lambda(); } int main() { LambdaWrapper w; useLambda(w.getLambda()); return 0; }
这段代码中,LambdaWrapper::getLambda()的返回值和useLambda()的参数都使用了auto。由于实际仅依赖getLambda()的返回类型,我们可以为该类型定义别名,在类外部定义是可行的:
struct LambdaWrapper { auto getLambda() { ... } static LambdaWrapper* get(); }; using LambdaType = decltype(LambdaWrapper::get()->getLambda()); void useLambda(const LambdaType &lambda);
但尝试将别名移入类内部时,出现编译错误:
struct LambdaWrapper { auto getLambda() { ... } static LambdaWrapper* get(); using LambdaType = decltype(LambdaWrapper::get()->getLambda()); }; void useLambda(const LambdaWrapper::LambdaType &lambda);
错误信息:
error: use of ‘auto LambdaWrapper::getLambda()’ before deduction of ‘auto’
请问如何在类内部定义该别名?
补充背景
问题源于对带捕获lambda的复杂range-view组合进行类型擦除的需求,且该组合类型会随视图的增减或修改变化。拟定的解决方案策略为:
- 在类体内定义内联方法,返回未类型擦除的实际复杂视图组合
- 依赖函数自动推导实际类型
- 用
decltype为该方法的返回类型定义别名 - 所有消费该视图组合的函数均使用该别名,以此隐藏实现复杂度,视图变化时消费端代码无需修改
目前可在类外定义别名,或通过继承、嵌套类增加间接性实现,但希望找到无需这类技巧的更优雅方案。
解决方案
方法1:利用C++20 requires延迟类型推导
借助requires子句强制编译器延迟类型计算,直到类的完整定义可见:
struct LambdaWrapper { auto getLambda() { return []() { std::cout << "Lambda is called" << std::endl; }; } static LambdaWrapper* get() { static LambdaWrapper instance; return &instance; } // 延迟推导至类定义完成后 using LambdaType = decltype(get()->getLambda()) requires true; }; void useLambda(const LambdaWrapper::LambdaType &lambda) { lambda(); } int main() { LambdaWrapper w; useLambda(w.getLambda()); return 0; }
方法2:将类型别名放在类末尾
确保定义别名时类的完整类型已可用,可分离getLambda()的声明与定义:
struct LambdaWrapper { auto getLambda(); // 先声明成员函数 static LambdaWrapper* get() { static LambdaWrapper instance; return &instance; } // 放在类最后,此时类的完整类型已可见 using LambdaType = decltype(get()->getLambda()); }; // 类外部定义getLambda() auto LambdaWrapper::getLambda() { return []() { std::cout << "Lambda is called" << std::endl; }; } void useLambda(const LambdaWrapper::LambdaType &lambda) { lambda(); } int main() { LambdaWrapper w; useLambda(w.getLambda()); return 0; }
方法3:使用C++17 std::invoke_result
借助std::invoke_result_t推导成员函数调用的返回类型,需保证函数声明先于别名:
#include <type_traits> struct LambdaWrapper { auto getLambda(); static LambdaWrapper* get() { static LambdaWrapper instance; return &instance; } // 通过成员函数指针推导返回类型 using LambdaType = std::invoke_result_t<decltype(&LambdaWrapper::getLambda), LambdaWrapper*>; }; auto LambdaWrapper::getLambda() { return []() { std::cout << "Lambda is called" << std::endl; }; } void useLambda(const LambdaWrapper::LambdaType &lambda) { lambda(); } int main() { LambdaWrapper w; useLambda(w.getLambda()); return 0; }
内容的提问来源于stack exchange,提问作者Dmitry Kuzminov
相关产品推荐
相关产品推荐

