How to make template rvalue reference parameter ONLY bind to rvalue reference?

前端 未结 5 2060
心在旅途
心在旅途 2020-12-01 08:59

I\'m writing a network library and use move semantics heavily to handle ownership for file descriptors. One of my class wishes to receive file descriptor wrappers of other k

5条回答
  •  暗喜
    暗喜 (楼主)
    2020-12-01 09:45

    Unfortunately, it seems like trying out is_rvalue_reference (where TF is the perfectly-forwarded type) does not work well if you are actually trying to make overloads that distinguish between const T& and T&& (e.g. using enable_if in both, one with is_rvalue_reference_v and the other with !is_rvalue_reference_V).

    A solution (albeit hacky) is to decay the forwarded T, then place the overloads in a container aware of these types. Generated this example:

    Hup, I was wrong, just forgot to look at Toby's answer (is_rvalue_reference) -- though it's confusing that you can do std::forward(...), but I guess that's why decltype(arg) also works.

    Anywho, here's what I used for debugging: (1) using struct overloads, (2) using the wrong check for is_rvalue_reference, and (3) the correct check:

    /*
    Output:
    
    const T& (struct)
    const T& (sfinae)
    const T& (sfinae bad)
    ---
    const T& (struct)
    const T& (sfinae)
    const T& (sfinae bad)
    ---
    T&& (struct)
    T&& (sfinae)
    const T& (sfinae bad)
    ---
    T&& (struct)
    T&& (sfinae)
    const T& (sfinae bad)
    ---
    */
    
    #include 
    #include 
    
    using namespace std;
    
    struct Value {};
    
    template 
    struct greedy_struct {
      static void run(const T&) {
        cout << "const T& (struct)" << endl;
      }
      static void run(T&&) {
        cout << "T&& (struct)" << endl;
      }
    };
    
    // Per Toby's answer.
    template 
    void greedy_sfinae(const T&) {
      cout << "const T& (sfinae)" << endl;
    }
    
    template <
        typename T,
        typename = std::enable_if_t::value>>
    void greedy_sfinae(T&&) {
      cout << "T&& (sfinae)" << endl;
    }
    
    // Bad.
    template 
    void greedy_sfinae_bad(const T&) {
      cout << "const T& (sfinae bad)" << endl;
    }
    
    template <
        typename T,
        typename = std::enable_if_t::value>>
    void greedy_sfinae_bad(T&&) {
      cout << "T&& (sfinae bad)" << endl;
    }
    
    template 
    void greedy(TF&& value) {
      using T = std::decay_t;
      greedy_struct::run(std::forward(value));
      greedy_sfinae(std::forward(value));
      greedy_sfinae_bad(std::forward(value));
      cout << "---" << endl;
    }
    
    int main() {
      Value x;
      const Value y;
    
      greedy(x);
      greedy(y);
      greedy(Value{});
      greedy(std::move(x));
    
      return 0;
    }
    

提交回复
热议问题