2012-06-25 2 views
1

템플릿 매개 변수에서 상속되고 특정 기본 멤버 함수의 오버로드를 모두 무시하는 템플릿 래퍼 클래스를 만들려고합니다. 다음 예는 다음과 같습니다 기본 멤버 함수의 모든 오버로드를 단일 템플릿 멤버 함수에서 재정의하고 전달할 수 있습니까?

#include <cassert> 
#include <string> 
#include <utility> 

template <class T> 
class Wrapper: public T { 
public: 
    template <typename... Args> 
    Wrapper<T>& operator=(Args&&... args) { 
    return this_member_fn(&T::operator=, std::forward<Args>(args)...); 
    } 

private: 
    template <typename... Args> 
    Wrapper<T>& this_member_fn(T& (T::*func)(Args...), Args&&... args) { 
    (this->*func)(std::forward<Args>(args)...); 
    return *this; 
    } 
}; 

int main(int, char**) { 
    Wrapper<std::string> w; 
    const std::string s("!!!"); 
    w = s; 
    assert(w == s); 
    w = std::string("???"); 
    assert(w == std::string("???")); 
    return 0; 
} 

아이디어는 Wrapper<T>::operator=의 템플릿은 앞으로 다음 해당 인수를 인수에 따라 컴파일시 = 올바른 T :: 연산자를 선택한 것입니다. (

test.cpp: In instantiation of ‘Wrapper<T>& Wrapper<T>::operator=(Args&& ...) [with Args = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; T = std::basic_string<char>]’: 
test.cpp:26:24: required from here 
test.cpp:10:69: error: no matching function for call to ‘Wrapper<std::basic_string<char> >::this_member_fn(<unresolved overloaded function type>, std::basic_string<char>)’ 
test.cpp:10:69: note: candidate is: 
test.cpp:15:15: note: Wrapper<T>& Wrapper<T>::this_member_fn(T& (T::*)(Args ...), Args&& ...) [with Args = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; T = std::basic_string<char>] 
test.cpp:15:15: note: no known conversion for argument 1 from ‘<unresolved overloaded function type>’ to ‘std::basic_string<char>& (std::basic_string<char>::*)(std::basic_string<char>)’ 
test.cpp: In member function ‘Wrapper<T>& Wrapper<T>::operator=(Args&& ...) [with Args = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; T = std::basic_string<char>]’: 
test.cpp:11:3: warning: control reaches end of non-void function [-Wreturn-type] 

라인 (26) w = std::string("???");과 라인 (15) this_member_fn의 선언, 그래서 컴파일러가 func을 생각하는 유형 보인다 : 나는

gcc -std=c++11 -W -Wall -Wextra -pedantic test.cpp -lstdc++ 

빌드하면 나는 GCC에서 다음 불만을 얻을 = std::string::operator=)가 기대했던 것이 아닙니다.

기본 클래스의 각 operator=을 개별적으로 재정의하는 것이 아니라 내가 템플릿을 사용하여 operator=을 사용하는 방법이 있습니까?

답변

4

그 자리에서 사용하려는 경우 회원 주소를 입력 할 필요가 없습니다. 이렇게하면 어느 오버로드 된 버전을 선택해야하는지 파악하는 데 어려움이 없습니다.

template< 
    typename U 
    , typename std::enable_if< 
     std::is_assignable<T&, U>::value 
     , int 
    >::type = 0 
> 
Wrapper& operator=(U&& u) 
{ 
    static_cast<T&>(*this) = std::forward<U>(u); 
    return *this; 
} 

제약 (std::enable_if를 통해 SFINAE 시험) 것을 적극 intWrapper<int>를 할당하는 시도가 실패합니다 Wrapper<int> w, v; w = v;처럼 간단 달리 무언가로 추천합니다. 제약 조건으로 특수 회원 Wrapper& operator=(Wrapper const&);이 올바르게 선택됩니다.

+1

어쨌든 당신은 'int'에서 상속받을 수 없습니다 :) +1 –

1

가 여러 std::string::operator=의, 그래서 T = std::string이 멤버 함수에 포인터를 초래하지 않을 표현 &T::operator=.

1

아니, function template can never be virtual, 그래서 재정 아무것도 할 수 없습니다.

하지만 당신은 가상이 아닌 함수 템플릿을 가질 수 있습니다 (그래서 아무것도 오버라이드 (override)하지 않음)하고 이름을 명시 적으로-자격으로 기본 클래스 함수를 호출 할 수 있습니다 :

this->T::operator=(std::forward<Args>(args)...); 
return *this; 

합니다 (this-> 사실입니다 가 필요하지만, 명확성을 위해 포함되어 있습니다.) &T::operator=와 버전이 명확하게 하나의 과부하의 이름이없는 반면

이것은 (그래서 하나의 함수의 주소가 아닌, T::operator= 이름를 오버로드 확인하여 올바른 기능을 선택합니다 전체 과부하 세트 및 과부하 세트가 첫 번째가 아닙니다. C++의 -class 객체는 함수에 전달 될 수 없습니다.

기본 클래스의 대입 연산자가 올바른 유형을 반환하지 않기 때문에 해당 표현식을 반환 할 수 없습니다. static_cast<Wrapper&>(...)을 사용할 수 있지만 *this을 반환하는 것이 더 쉽습니다.

+0

'Wrapper :: operator ='의 본문을 대체하여 * 작동합니다 * (실제로는 이전에 사용했던 것임).하지만 보조 함수를 사용하여'std :: string :: assign'과'std :: string :: replace'와 같은'T &'를 반환하는 다른 멤버 함수에 대한 오버로드를 생성 할 수 없다는 것을 의미합니다. 내가 바라는 것이 었습니다. – uckelman

+0

기본 함수가 오버로드되면'& T :: foo'가 애매하기 때문에 일반적으로 작동하지 않습니다. 예를 들어를 통해이를 해결할 수 있습니다. 'static_cast (& T :: operator =)'하지만 미리 원하는 과부하를 알아야합니다. –

관련 문제