3

최근 범용 (또는 전달) 참조에 대해 배웠습니다. 템플릿과 같은 유형 공제 또는 auto/decltype과 함께 작동합니다.형식 공제없이 동작과 같은 전달 참조를 얻을 수 있습니까?

lvalue-reference (&)를 사용할 때 rvalue (임시) 개체에 바인딩 할 수 없습니다. rvalue-reference (& &)를 사용하면 lvalue 객체에 바인드 할 수 없습니다. 전달 참조는 const가 아닌 lvalues와 rvalues ​​모두에서 작동 할 수 있습니다.

유형 공제없이 전달 참조 동작을 달성 할 수 있습니까?

void Foo(string && s); // rvalue-reference 
void Bar(const string & s); // const lvalue-reference 
void Baz(auto && s); // forwarding reference 

string s = "lvalue string"; 

Foo(s);  // error: cannot bind lvalue to && 
Foo("test"); // OK 

// works, but can't take non-const value 
Bar(s); 
Bar("test"); 

// works 
Baz(s); 
Baz("test"); 
+0

'const &'는'&&'가 존재하기 전에 어떻게 행해졌습니까. – NathanOliver

+2

SFINAE를 사용하여 항상 유형을 제한 할 수 있습니다. – Rakete1111

+0

'lvalue-reference (&)를 사용할 때 비 const 객체에 바인딩 할 수 없습니다. 물론 lvalue-reference를 const가 아닌 객체에 바인딩 할 수 있습니다. 아마도 당신은 const가 아닌 참조가 const 객체에 바인딩 할 수 없다는 것을 의미했을까요? 또는 비 const 레퍼런스는 (임시처럼) rvalue에 바인딩 할 수 없습니까? – user2079303

답변

2

일종의. T에 대한 정방향 참조 개념을 입력하여 지울 수 있습니다.

template<class T> 
struct forward_ref { 
    using extract_sig = T(void*); 
    using get_sig = T const&(void*); 

    extract_sig* extract = nullptr; 
    get_sig* gettor = nullptr; 

    void* pvoid; 


    template<class U> 
    void wrap(U&& t) { 
    auto* pt = std::addressof(t); 
    using pT = decltype(pt); 
    pvoid = const_cast<void*>(static_cast<void const*>(pt)); 
    gettor = [](void* pvoid)->T const& { 
     // std::cout << "getting:\n"; 
     auto* pt = static_cast<pT>(pvoid); 
     return *pt; 
    }; 
    extract = [](void* pvoid)->T { 
     // std::cout << "extracting via " << (std::is_rvalue_reference<U&&>::value?"move":"copy") << "\n"; 
     auto* pt = static_cast<pT>(pvoid); 
     return std::forward<U>(*pt); 
    }; 
    } 

    forward_ref(T const& t){ wrap(t); } 
    forward_ref(T && t = {}){ wrap(std::move(t)); } 


    bool valid() const { return gettor&&extract; } 
    operator T()&&{ 
    // std::cout << "operator T&&\n"; 
    T r = extract(pvoid); 
    // std::cout << "extracted\n"; 
    gettor=nullptr; extract=nullptr; pvoid=nullptr; 
    return r; 
    } 
    operator T const&() const &{ 
    // std::cout << "operator T const&\n"; 
    return gettor(pvoid); 
    } 
    T get()&& { return std::move(*this); } 
    T const& get() const& { return *this; } 
}; 

그래서 당신은이 작업을 수행 할 수 있습니다

void Foo(forward_ref<std::string> s); // rvalue-reference 

std::string에 전달 유사한 참조 s 동작합니다을 (어느 정도).

std::moves 인 경우 수신 된 std::string을 복사하거나 그 값이 rvalue 또는 lvalue인지에 따라 이동합니다.

지금이

void Foo(std::string s) 

이 될 것입니다 때문에 거의 위의 그 화려한 forward_ref보다 더 나은 생각을가는 요리, 꽤 바보입니다.

이동이 저렴하고 복사본을 stprimg 할 계획이라면 값을 가져 오는 것이 전달 참조와 거의 비슷합니다.

이동이 복사보다 저렴하면 const&으로 가져 가십시오.

이동이 비싸고 복사가 훨씬 비쌉니다.

전달 참조는 일반적인 코드에서 이동이 저렴하다는 것을 모르기 때문에 유용합니다. 당신이 아는 구체적인 유형.

어쨌든 live example은 정방향 참조를 삭제했습니다.