如何间接使用forwarding references?探讨间接场景下转发引用的实现
Great question! Let's unpack indirect forwarding references step by step—they're just an extension of the direct T&& forwarding references you know, but with a layer of abstraction. The core rule still applies: as long as the type parameter is deduced (not fixed), we can create a forwarding reference indirectly.
How to Use Indirect Forwarding References
Here are the most common, practical ways to implement them:
1. Via Alias Templates
This is the simplest indirect approach—we wrap T&& in a template alias, then use that alias in our function template. Since the function's template parameter is still deduced, the alias retains all forwarding reference behavior.
#include <utility> #include <iostream> // Target functions to demonstrate forwarding void process(int& x) { std::cout << "Handling lvalue: " << x << "\n"; } void process(int&& x) { std::cout << "Handling rvalue: " << x << "\n"; } // Alias template to wrap the forwarding reference template<typename T> using ForwardingRef = T&&; // Indirect forwarding function template<typename T> void indirect_forwarder(ForwardingRef<T> arg) { process(std::forward<T>(arg)); // Forward just like with direct references } int main() { int val = 42; indirect_forwarder(val); // Binds to lvalue, T deduces to int& indirect_forwarder(123); // Binds to rvalue, T deduces to int }
2. In Class Template Member Functions
To use indirect forwarding references in a class template, you need to define a member function template (not just use the class's template parameter). This ensures the type parameter for the forwarding reference is deduced, not fixed by the class's instantiation.
#include <utility> #include <iostream> void process(int& x) { std::cout << "Handling lvalue: " << x << "\n"; } void process(int&& x) { std::cout << "Handling rvalue: " << x << "\n"; } template<typename Container> class DataHandler { public: // Alias template inside the class for indirect forwarding template<typename T> using ForwardingRef = T&&; // Member function template with indirect forwarding template<typename T> void handle(ForwardingRef<T> arg) { process(std::forward<T>(arg)); } }; int main() { DataHandler<int> handler; int val = 42; handler.handle(val); // Lvalue binding handler.handle(123); // Rvalue binding }
3. Nested with auto&& (C++14+)
auto&& is a form of forwarding reference (often called a universal reference) on its own. Using it in nested contexts like lambdas inside template functions counts as indirect usage, and it works exactly as you'd expect.
#include <utility> #include <iostream> #include <functional> void process(int& x) { std::cout << "Handling lvalue: " << x << "\n"; } void process(int&& x) { std::cout << "Handling rvalue: " << x << "\n"; } template<typename Func> void execute_wrapper(Func func) { // Lambda uses auto&& as an indirect forwarding reference auto wrapped = [func](auto&& arg) { func(std::forward<decltype(arg)>(arg)); }; int val = 42; wrapped(val); // Forward lvalue wrapped(123); // Forward rvalue } int main() { execute_wrapper([](auto&& arg) { process(std::forward<decltype(arg)>(arg)); }); }
Can You Use Forwarding References in Indirect Scenarios?
Absolutely—any scenario where you can have a deduced type parameter will work for indirect forwarding references. The only catch is avoiding non-deduced contexts: if the type parameter can't be deduced from the function argument (e.g., typename Wrapper<T>::type), then T&& becomes a plain rvalue reference, not a forwarding reference.
For example, this won't work as a forwarding reference:
template<typename T> struct BadWrapper { using type = T&&; }; template<typename T> void bad_forwarder(typename BadWrapper<T>::type arg) { // arg is a rvalue reference, NOT a forwarding reference // T can't be deduced here—you'd have to explicitly specify it, which breaks forwarding }
内容的提问来源于stack exchange,提问作者Antoine Morrier

