如何强制Lambda非限定调用时选择全局scopePrint而非成员函数
解决方案:根据上下文自动选择正确的
scopePrint()调用 C++20 标准方案(推荐)
利用C++20的requires表达式在编译期检测当前上下文是否存在this指针,从而决定调用成员函数还是全局函数。修改后的log()宏及完整代码如下:
#include <iostream> #include <string> #define log() \ do { \ using namespace Game; \ int foo = 1 + 1; \ [&]() noexcept { \ if constexpr (requires { this->scopePrint(); }) { \ this->scopePrint(); \ } else { \ ::Game::scopePrint(); \ } \ }(); \ int bar = 1 + 1; \ } while (0) namespace Game { void scopePrint() { std::cout << "I'm in the global scope!\n"; } struct Character { void scopePrint() { std::cout << "I'm in Character " << name_ << "'s scope!\n"; } void takeTurn() { auto runCalculation = []() { int foo = 1 + 1; log(); // 编译通过,调用全局scopePrint }; runCalculation(); log(); // 调用Character::scopePrint,打印成员作用域信息 } std::string name_; }; } // ns Game int main(){ using namespace Game; Character character{"John"}; character.takeTurn(); log(); // 调用全局scopePrint,打印全局作用域信息 return 0; }
原理说明
requires { this->scopePrint(); }会在编译期检查当前上下文是否能合法调用this->scopePrint():- 在
Character的成员函数(如takeTurn())中,this存在且指向当前对象,检测结果为true,调用成员函数scopePrint(); - 在无捕获Lambda或全局上下文(如
main())中,this不存在,检测结果为false,调用全局命名空间下的::Game::scopePrint();
- 在
- 用Lambda包裹判断逻辑,确保
this的检测在正确的上下文中进行。
非C++20 替代方案(依赖GCC扩展)
若无法使用C++20,可借助GCC的__builtin_this_pointer扩展,结合SFINAE检测类是否存在scopePrint成员函数:
#include <iostream> #include <string> #include <type_traits> namespace Game { // 检测类是否包含scopePrint成员函数的SFINAE工具 template<typename T> struct has_scope_print { private: template<typename U> static auto test(int) -> decltype(std::declval<U>().scopePrint(), std::true_type{}); template<typename U> static std::false_type test(...); public: static constexpr bool value = decltype(test<T>(0))::value; }; void scopePrint() { std::cout << "I'm in the global scope!\n"; } } // ns Game #define log() \ do { \ using namespace Game; \ int foo = 1 + 1; \ auto __this_ptr = __builtin_this_pointer; \ if constexpr (std::is_pointer_v<decltype(__this_ptr)> && __this_ptr != nullptr) { \ using __ClassType = std::remove_pointer_t<decltype(__this_ptr)>; \ if constexpr (has_scope_print<__ClassType>::value) { \ static_cast<__ClassType*>(__this_ptr)->scopePrint(); \ } else { \ ::Game::scopePrint(); \ } \ } else { \ ::Game::scopePrint(); \ } \ int bar = 1 + 1; \ } while (0) namespace Game { struct Character { void scopePrint() { std::cout << "I'm in Character " << name_ << "'s scope!\n"; } void takeTurn() { auto runCalculation = []() { int foo = 1 + 1; log(); // 编译通过,调用全局scopePrint }; runCalculation(); log(); // 调用Character::scopePrint } std::string name_; }; } // ns Game int main(){ using namespace Game; Character character{"John"}; character.takeTurn(); log(); // 调用全局scopePrint return 0; }
原理说明
__builtin_this_pointer是GCC扩展,在成员函数中指向当前对象,在非成员函数中为nullptr;- 通过SFINAE工具
has_scope_print检测当前类是否包含scopePrint成员函数,从而选择对应的调用逻辑。
内容的提问来源于stack exchange,提问作者mgperry
相关产品推荐
相关产品推荐

