2013-06-21 2 views
10

C++ 03에서 작업 중이며 C++ 11의 delete d 기능을 사용할 수 없습니다.컴파일러가 C++에서 암시 적으로 선언 된 복사본 생성자를 고려하지 못하게 함 03

복사 할 수없는 개체를 디자인하려고 시도하고 있으며 해당 클래스에서 암시 적으로 선언 된 복사본 생성자를 고려하지 않도록하고 있습니다. 이것은 내가 개발하고있는 단위 테스트 장치를위한 것입니다.

내가 두 가지 목적을 가지고 생각해 핵심 라이브러리 오브젝트, Root, 테스트에서 파생 특별한 경우 객체 Branch. 나는 Fixture이라는 테스트 픽스처 클래스를 개발하려고하는데, Root 오브젝트와 & 오브젝트를 설정하는 것이 중요하다. 그래서 내가 지금까지 구축 한 내용의 단순화 된 그림입니다 :

(I 정의한 제외 Here is an ideone link 다음과 같은 코드는 내 자신의 noncopyable)

#include <boost/utility.hpp> 
#include <boost/noncopyable.hpp> 

class Root 
{ 
}; 

class Fixture 
: 
    public boost::noncopyable 
{ 
public: 
    Fixture (Root& root) 
    : 
     mRoot (root) 
    { 
    } 
private: 
    Root& mRoot; 
}; 

class Branch 
: 
    public Root, 
    public Fixture 
{ 
public: 
    Branch() 
    : 
     Fixture (*this) 
    { 
    } 
}; 

int main() 
{ 
    Branch branch; 
} 

이 결과 컴파일 :

main.cpp: In constructor ‘Branch::Branch()’: 
main.cpp:30:23: error: call of overloaded ‘Fixture(Branch&)’ is ambiguous 
main.cpp:30:23: note: candidates are: 
main.cpp:13:5: note: Fixture::Fixture(Root&) 
main.cpp:8:7: note: Fixture::Fixture(const Fixture&) 

적어도 하나는 스스로 선언하지 않으면 C++ 03 컴파일러가 Fixture의 복사 생성자를 암시 적으로 선언하지 못하게 할 수 없습니다.

Fixture (*this) 

은 단순히이 복사 생성자를 고려하지 컴파일러를 원하는 :하지만 심지어와 함께 : Branch의 초기화 목록에 Fixture을 초기화 할 때

class Fixture 
: 
    public boost::noncopyable 
{ 
public: 
    Fixture (Root& root) 
    : 
     mRoot (root) 
    { 
    } 
private: 
    Fixture (const Fixture&); 
    Fixture (Fixture&); 
    Root& mRoot; 
}; 

... 컴파일러는 여전히 이러한 private 선언을 고려할 것 . 그것은 내 코와 비 복사 기능에 약간의 냄새의로,

Fixture (static_cast <Root&> (*this)) 

을 ...하지만 차라리하지 않는 게 좋을 :

난 내 자신에 조금 contorting을 수행하여이 작업을 수행 할 수 의미 에서 Fixture을 파생 시켜서 내가 무엇을 할거야.

에서 호출 사이트에서 코드를 변경하지 않고이 경우 암시 적으로 선언 복사 생성자를 고려에서 컴파일러를 방지 할 수있는 방법이 있나요 :

Fixture (*this) 

은?


  • 는 "그것은 불가능하다 ...": 표준 C++ 03 : 12.8/4, "특수 멤버 함수":

클래스 정의가 명시 적으로하지 않는 경우 생성자 복사본을 선언하면 하나가 암시 적으로 선언됩니다.

+2

C++ 11의 삭제 된 기능은 도움이 될까요? 삭제 된 기능은 여전히 ​​과부하 해결에 참여합니다. –

+0

@KerrekSB : 솔직히, 나는 모른다. 당신이 결의안에 참여하는 것이 옳다면, 그들은 도움을주지 않을 것이라고 생각합니다. –

+0

[templated constructor] (http://ideone.com/nHhzEi)이 명확하게 우선해야한다고 생각합니다 ... –

답변

4

귀하의 모호성은 *this가 모두 Root &Fixture &에 결합 할 수 있다는 것입니다, 모두 전환은 동등하게 좋은 (즉 파생 투베이스 변환)은 다음과 같습니다 간단한 예는 다음과 같습니다.

트릭은 의 더 좋은 과부하를 생성하는 것입니다. 예를 들어,

template <typename T> Fixture(T &) 

는 좌변 정확히 일치합니다, 따라서 변환을 필요로하는 과부하보다 더 나은 경기입니다.

실제로는 ­ 것으로부터 Fixture을 생성 할 수 없기 때문에 너무 순진합니다. 오히려 당신은 그것이 Root에서 유래 한 것에서 만 구성 가능하기를 원합니다. 우리는 SFINAE 마술을 사용하여 불필요한 생성자를 비활성화 할 수 있습니다. 먼저 C++ 11 버전 :

#include <type_traits> 

template <typename T, 
      typename = typename std::enable_if<std::is_base_of<Root, T>::value>::type> 
Fixture(T & x) 
: mRoot(x) 
{ } 

C++ 03에서, 우리는 부스트를 사용하여, 우리는 기본 템플릿 인수를 사용할 수 없습니다 당신이 T가 도출되는 것을 보장 이제

#include <boost/type_traits.hpp> 

template <typename T> 
Fixture(T & x, 
     typename boost::enable_if<boost::is_base_of<Root, T> >::type * = NULL) 
: mRoot(x) 
{ } 

RootT = Branch이있는이 템플릿 생성자의 오버로드는 복사 생성자보다 정확하게 일치하므로 명확하게 최고의 오버로드로 선택됩니다.

+0

그'enable_if'로,이 과부하는 더 이상'Branch &'를 위해 실행 가능하지 않습니다. 어쩌면'is_convertible '. – aschepler

+0

나는 SFINAE 마법이 여기에 조금 부족하다고 생각하지만 도와 줄 수는 없다. 난 단순한'template' 생성자 (SFINAE가 아닌)로 모든것에 뒤떨어져 있습니다. 변환 할 수없는 것을 전달하면 ('FooBar'), 컴파일이 실패 할 것입니다. –

+0

'is_same'이이 시나리오에서 컴파일되지 않을 것이기 때문에 분명히 작동하지 않을 것입니다. 그리고 제가 말했던 것처럼 C++ 03을 사용하고 있습니다. 내가 고칠거야. –

3

C + + 98이 아닌 C + + 11에서도 복사본 생성자 시그너처의 존재를 방지 할 수있는 방법이 없습니다. = delete은 과부하 세트에서 무언가를 제거하지 않으며 선택되면 실패합니다.

Fixture의 공용 인터페이스를 엉망으로 만들고 싶지 않은 경우 명시 적 형변환을 삽입하는 것보다 더 좋은 아이디어는 없습니다.

인터페이스를 엉망으로 만드는 옵션은 복사 생성자의 참조와 구별하기 위해 포인터로 Root을 전달하고 과부하 해결을 위해 태그를 전달하는 것을 포함합니다. 이것들에 대해 더 알고 싶다면 코멘트를 남겨주세요.

+0

+1 포인터를 전달할 수 있지만 참조를 저장하는 대신 참조를 전달하고 싶습니다. 포인터를 가져 오기 위해 ctor를 변경하면 어쨌든 호출 사이트 코드를 변경해야하므로이 경우'static_cast'를 선호합니다. –

+0

Btw, 나는 'Branch'에서 콜 사이트 코드를 변경하지 않는 한'Fixture'의'public' 인터페이스를 엉망으로 만들었습니다. –

2

Fixture의 인스턴스로 전달하지 않으려는 경우 상속 할 필요가 전혀 없습니다. 당신이 기본적으로하고 싶은 것은 내가 실수하지 않는다면 Root의 모든 인스턴스에 대해 Fixture에 뭔가를 설정할 수 있습니다. 따라서 C++를 구부리기보다는 공격을 유발할 수 있습니다. 면책 조항 : 그렇지 않은 경우 제안이 없습니다. 두려워합니다. 그것은 결코에 Fixture의 생성자와 할당 연산자로 인스턴스 자체를 전달하여 Fixture의 인스턴스를 생성하는 멤버와 Branch의 과부하 복사 생성자의로

이 문제에 대한

, 나는 BranchFixture의 인스턴스를 만들 것 Fixture 인스턴스를 복사하십시오.

#include <boost/utility.hpp> 
#include <boost/noncopyable.hpp> 

class Root 
{ 
}; 

class Fixture 
: 
    public boost::noncopyable 
{ 
public: 
    Fixture (Root& root) 
    : 
     mRoot (root) 
    { 
    } 
private: 
    Root& mRoot; 
}; 

class Branch 
: 
    public Root 
{ 
public: 
    Branch() 
    : mFixture(*this) 
    { 
    } 

    Branch(const Branch& branch) 
    : Root(*this) 
    , mFixture(*this) 
    /* other 'Branch' members to be copied */ 
    { 
    } 

    Branch& operator = (const Branch& branch) 
    { 
     Root::operator=(branch); 
     /* copy other 'Branch' members, except 'mFixture' */ 
    } 

    Fixture& getFixture() 
    { 
     return mFixture; 
    } 

    const Fixture& getFixture() const 
    { 
     return mFixture; 
    } 

private: 
    Fixture mFixture; 
}; 
관련 문제