2017-12-27 1 views
3

공제 가이드가 범용 참조 및 std::forward과 함께 작동하는 방법, 특히 완벽하게 전달하는 래퍼를 만드는 방법을 알고 싶습니다. 아래의 코드는 펑터 래퍼 (implator)가있는 경우와 명시 적 공제 가이드가있는 경우의 두 가지 경우에서 펑터 래퍼 (functor wrapper)를 실험 할 수있는 코드를 제공합니다.클래스 템플릿 인수 공제와 함께 완벽한 전달

완벽한 전달을 위해 어디에 필요한지 알 수 없기 때문에 나는 &&std::forward을 많이 썼습니다. 나는 그 (것)들을 어디에 두어야하는지, 그리고 그것이 필요하지 않은 곳을 알고 싶다.

// Case with not conversion constructor 
template <class F> 
struct functor1 
{ 
    explicit constexpr functor1(F/*&&*/ f) 
    noexcept(std::is_nothrow_copy_constructible_v<F/*&&*/>) 
    : _f(/*std::forward<F>(*/f/*)*/) 
    {} 
    template <class... Args> 
    constexpr operator()(Args&&... args) 
    noexcept(std::is_nothrow_invocable_v<F/*&&*/, Args/*&&*/...>) 
    { 
     /*std::forward<F>(*/_f/*)*/(std::forward<Args>(args)...); 
    } 
    private: F/*&&*/ _f; 
}; 

// Case with a conversion constructor 
template <class F> 
struct functor2 
{ 
    template <class G> 
    explicit constexpr functor2(G&& g) 
    noexcept(std::is_nothrow_constructible_v<G/*&&*/, F/*&&*/>) 
    : _f(/*std::forward<G>(*/g/*)*/) 
    {} 
    template <class... Args> 
    constexpr operator()(Args&&... args) 
    noexcept(std::is_nothrow_invocable_v<F/*&&*/, Args/*&&*/...>) 
    { 
     /*std::forward<F>(*/_f/*)*/(std::forward<Args>(args)...); 
    } 
    private: F/*&&*/ _f; 
}; 
template <class G> 
functor2(G&&) -> functor2<G/*&&*/>; 

편집 : 단순의 술과는 앞의 예에서, 질문의 요점이 아니기 때문에, 우리는 FG 기능이 operator()으로 즉, 클래스/구조체를 객체 것을 고려하십시오.

답변

1

C++ 표준에서는 전달 참조을 정의합니다. 이 용어의 동의어로 범용 참조이 사용됩니다. [temp.deduct.call]/3

착신 기준 클래스 템플릿 템플릿 매개 변수를 나타내지 않는 CV-비정규 템플릿 파라미터 r- 수치로 기준이다.

이 개념은 템플릿 함수 인수 또는 템플릿 생성자 인수에만 적용됩니다. 다른 모든 경우에 T&&이며 참조 번호입니다. 포워딩 참조의 개념은 템플릿 인수 공제에만 유용합니다.

//possibilities of argument deduction, [cv] means any combination of "const" and "volatile": 
// <"","const","volatile","const volatile"> 
template<class T> void f(T&); 
    //4 possibilities: void f([cv] int&); 

template<class T> void f(const T&); 
    //2 possibilities: void f(const int&); 
        //void f(const volatile int&); 

template<class T> void f(T&&); 
    //Forwarding reference, 8 possibilities 
      //void f([cv] int&); 
      //void f([cv] int&&); 

template<class T> void f(const T&&); 
    //NOT a forwarding reference because of the const qualifier, 2 possibilities: 
      //void f(const int&&); 
      //void f(const volatile int&&); 

template<class T> 
struct S{ 
    template<class U> 
    S(U&&); 
     //Forwarding reference, 8 posibilities: 
      //void S<X>([cv] int&); 
      //void S<X>([cv] int&&); 
     //no template argument deduction posible 

    S(T&&); 
     //NOT a forwarding reference, 1 possibility: 
      //void S<X>(X&&); 
     //Generated argument deduction: 
     //template<class T> S(T&&) -> S<T>; 
      //not a forwarding reference because T is a parameter of the template class; 
      //=> 4 possibilities: -> S<[cv] int&&> 


    T&& a; //an rvalue reference if T is [cv] int or [cv] int&&, 
      //an lvalue reference if T is [cv] int&; 
      //This comes from reference colapsing rules: &+&=&; &&+&=&; &&+&&=&&  //(Nota: You may consider that a rvalue reference data member is probably a mistake) 
}; 

template<class U> 
S(U&&) -> S<U&&>; 
//Forwarding reference, 8 possibilities: 
// S<[cv] int&>; 
// S<[cv] int&&>; 

만의 체내 std::forward 메이크업 감각을 사용하여 다음의 다음과 같은 예에서 것을 생각해 보자, 모든 fonctions 및 생성자는 (독립적으로 const와 가치 범주 (좌변 /를 rvalue)의 int 인수와 함께 호출 함수 또는 생성자 std::forward의 인수가 템플릿 인수 공제 및 참조 축소 규칙에 따라 rvalue 참조 또는 lvalue 참조 일 수있는 경우 std::forward의 인수가 항상 rvalue 참조가되는 경우 std::move이 선호되며 항상 lvalue를 참조하면 아무 것도 바람직하지 않습니다.

관련 문제