std::mem_fn调用带__forceinline的成员函数未内联的原因与解决问询
Great question! Let's break this down step by step:
__forceinline Member Function Isn't Being Inlined with std::mem_fn Yes, the root cause here is almost certainly that the standard implementation of std::mem_fn doesn't include forced inline attributes (like __forceinline, __attribute__((always_inline)), etc.) on its call operator.
When you wrap a member function with std::mem_fn, you're not calling the function directly—you're calling std::mem_fn's operator(), which then dispatches to your member function. If that intermediate operator() isn't marked for forced inlining, the compiler might choose to keep it as a separate function call. This breaks the "inline chain," preventing your __forceinline member function from being expanded at the original call site, even if you marked it explicitly.
mem_fn? Absolutely! You can create a simplified, custom version of mem_fn and mark its call operator with the appropriate forced inline attribute for your compiler. This gives the compiler the hint it needs to eliminate the intermediate wrapper and inline your target member function.
Example Implementation (Cross-Platform Friendly)
Here's a version that handles both const and non-const member functions, with cross-platform inline attributes:
#include <utility> #include <type_traits> // Cross-platform forced inline macro #if defined(_MSC_VER) #define FORCE_INLINE __forceinline #elif defined(__GNUC__) || defined(__clang__) #define FORCE_INLINE __attribute__((always_inline)) #else #define FORCE_INLINE inline #endif template <typename Ret, typename Class, typename... Args> struct MyMemFn { Ret (Class::*target_func)(Args...); explicit MyMemFn(Ret (Class::*func)(Args...)) : target_func(func) {} // Call operator for non-const objects FORCE_INLINE Ret operator()(Class& obj, Args&&... args) const { return (obj.*target_func)(std::forward<Args>(args)...); } // Call operator for const objects (matches const-qualified member functions) FORCE_INLINE Ret operator()(const Class& obj, Args&&... args) const requires std::is_member_function_pointer_v<Ret (Class::*)(Args...) const> { return (obj.*static_cast<Ret (Class::*)(Args...) const>(target_func))(std::forward<Args>(args)...); } }; // Helper to auto-deduce template parameters for non-const functions template <typename Ret, typename Class, typename... Args> FORCE_INLINE MyMemFn<Ret, Class, Args...> my_mem_fn(Ret (Class::*func)(Args...)) { return MyMemFn<Ret, Class, Args...>(func); } // Helper for const-qualified member functions template <typename Ret, typename Class, typename... Args> FORCE_INLINE MyMemFn<Ret, Class, Args...> my_mem_fn(Ret (Class::*func)(Args...) const) { return MyMemFn<Ret, Class, Args...>(static_cast<Ret (Class::*)(Args...)>(func)); }
Usage Example
class MyClass { public: __forceinline int add(int a, int b) const { return a + b; } __forceinline void set_value(int val) { value = val; } private: int value = 0; }; int main() { MyClass obj; // Call const member function auto sum = my_mem_fn(&MyClass::add)(obj, 4, 6); // Call non-const member function my_mem_fn(&MyClass::set_value)(obj, sum); // Both functions should be inlined at the call site return obj.value; }
Key Notes
- Compiler Behavior: Even with forced inline attributes, compilers can still refuse to inline in edge cases (e.g., extremely large functions, recursive logic, or low optimization levels). But this approach will drastically improve the odds of your
__forceinlinefunction being expanded compared tostd::mem_fn. - Feature Parity: The standard
std::mem_fnsupports more edge cases (like volatile objects, ref-qualified member functions, or pointer-to-member data). Extend your custom implementation only if you need those features—keep it simple for your specific use case. - Optimization Levels: Make sure you're compiling with sufficient optimization flags (e.g.,
/O2for MSVC,-O3for GCC/Clang) — without these, even forced inline hints might be ignored.
内容的提问来源于stack exchange,提问作者user8434768

