2013-06-20 11 views
8

이가 유효하도록 클래스를 작성하는 것이 가능 :암시 적 초기화를 0으로 오버로드 할 수 있습니까?

Foo a; 
Foo b = 0; 
Foo c = b; 
Foo d(0); 
Foo e(1); 
Foo f = Foo(1); 

를하지만이는 그렇지 않다 :

int x; 
Foo a = x; 
Foo b = 1; 
Foo c = 2; 
//etc 

기본적으로 내 규칙이 상수 0Foo에 암시 적으로 변환이다 "입니다 다른 값은 없습니다. "

+0

'Foo e (1);'은 어떨까요? 어떻게 유효합니까? –

+0

@ LuchianGrigore : 의미 상 동일합니까? 그렇다면 무효라고 선언 할 수 있다고 생각합니다. – Eric

+1

아마도'std :: nullptr_t'를 사용하여 생성자를 시도해 볼 수 있습니다 (단지 아이디어입니다 ...) –

답변

5

Foo b = nullptr;이 작동하지 않는다면 쉽게 해킹 할 수 있습니다. 명시 적 생성자는 int이고 암시 적은 std::nullptr_t입니다.

작동하는 것이 마음에 드신다면 가능하지 않을 수 있습니다. 리터럴 0과 다른 정수 리터럴을 구별하는 유일한 방법은 이전의 암시 적 포인터 변환과 nullptr_t입니다. 따라서 nullptr은 포인터 매개 변수에 nullptr_t 매개 변수를 선호하므로 두 생성자를 모두 사용하여 nullptr 인수를 필터링 할 수 있습니다. 그러나 0에서 포인터로의 변환과 nullptr_t의 변환은 동일한 순위이므로 0 인수를 모호하게 만듭니다.

흠 ... 이런 식으로 뭔가 작동 할 수 있습니다

class Foo { 
    struct dummy; 
public: 
    explicit Foo(int); // the version that allows Foo x(1); 
    Foo(dummy*); // the version that allows Foo x = 0; 
    template <typename T, 
      typename = typename std::enable_if< 
       std::is_same<T, std::nullptr_t>::value>::type> 
    Foo(T) = delete; // the version that prevents Foo x = nullptr; 
}; 

실제로이 시도하지 않았습니다. 이론적으로 템플릿은 인수가 nullptr 일 때만 과부하 해결에 참여해야합니다. 그렇지 않으면 SFINAE가이를 없애기 때문입니다. 그러나이 경우 포인터 생성자보다 좋을 것입니다.

0
Foo e(1); 

인수로서 int를 취하는 Foo의 명시 적이 지 않은 생성자. 이 int 생성자를 사용하여 int를 Foo로 변환하려고하면이 행이 동일하게 수행됩니다.

Foo b = 1; 

해당 int의 특정 값을 직접 처리 할 수 ​​없습니다. 생성자가 explicit 인 경우 다음 줄도 쓸 수 없습니다.

Foo b = 0; 

gx_는 0을 std :: nullptr_t로 변환 할 수 있다고 올바르게 명시했습니다. 다음은 귀하의 의도와 관련하여 작동합니다. 내가 가진

Foo(std::nullptr_t x) : member(0) { } 
explicit Foo(int c) : member(c) { } 
// ... 
Foo a = 0; // compiles 
Foo b = 1; // doesn't compile 

// Note: 
int do_stuff (void) { return 0; } 
Foo c = do_stuff(); // doesn't compile 
+0

아니 직접, 복사 초기화. –

+1

'명시적인 Foo (int);와 Foo (nullptr_t); –

+0

+1, 오히려 옆으로 생각할 수도 있지만 가능합니다. – Pixelchemist

-1

하나의 아이디어였다

Foo(const uint32_t c) : member(0) { static_assert(c == 0, "Nope"); } 
explicit Foo(uint32_t c) : member(c) { } 

이 현명하게 행동 하는가?

+2

컴파일되지 않습니다. 오버로드 해상도에 관한 한,'const uint32_t' 매개 변수와'uint32_t' 매개 변수는 같은 것입니다. –

-1

나는 아직 C++ (11)를 rvalue 의미의 완전한 숙달을 달성하지 않은 인정, 그러나 이것은 당신이 원하는 것을 할 것 같다 :

class Foo 
{ 
    public: 
    Foo(int&&) {} 
}; 

int main() 
{ 
    Foo a(123); 
    int x = 123; 
    Foo b(x); // error here, line 11 
    return 0; 
} 

결과 :

prog.cpp:11: error: cannot bind ‘int’ lvalue to ‘int&&’

댓글 환영합니다.이 코드에 눈치 채지 못했거나, 그렇지 않다는 것을 안심시킬 수 있다면.

+0

흥미 롭습니다. 그러나 저는'x == 0'의 특별한 경우를 목표로합니다. – Eric

+0

@eric 아, 그걸 몰랐어. 당신은'Foo e (1);'이 유효해야한다고 말했습니다 : / – Oktalist