2011-02-21 1 views
3

나는 다음과 같이 템플릿 클래스 내부 decltype를 사용하는 것을 시도하고있다 : 잘 작동decltype은

#include <functional> 
template <typename T> 
class A 
{ 
    typedef decltype(std::bind(&A::f, std::declval<A>())) some_type; 

    void f(); 
}; 

,하지만 지금은 명시 적 전문성을 추가하고 싶습니다 :

template <> 
class A<void> 
{ 
    typedef decltype(std::bind(&A::f, std::declval<A>())) some_type; 

    void f(); 
}; 

이번에는 g ++에서 오류를 제공합니다 :

test.cpp:14:33: error: incomplete type 'A<void>' used in nested name specifier 

내가 뭘 잘못하고 있니? 나는 gcc 4.5를 사용하고있다.

편집 : 요하네스 의해 제안 내가의 형식 정의 위에 void f();의 선언을 이동하면, 내가 할 (약간) 다른 오류 :

test.cpp:15:62: error: invalid use of incomplete type 'class A<void>' 
test.cpp:13:1: error: declaration of 'class A<void>' 
test.cpp:15:62: error: initializing argument 2 of 'std::_Bind<typename std::_Maybe_wrap_member_pointer<_Tp>::type(_ArgTypes ...)> std::bind(_Functor, _ArgTypes ...) [with _Functor = void (A<void>::*)(), _ArgTypes = {A<void>}, typename std::_Maybe_wrap_member_pointer<_Tp>::type = std::_Mem_fn<void (A<void>::*)()>]' 
test.cpp:15:62: error: invalid use of incomplete type 'class A<void>' 
test.cpp:13:1: error: declaration of 'class A<void>' 
test.cpp:15:62: error: initializing argument 2 of 'std::_Bind<typename std::_Maybe_wrap_member_pointer<_Tp>::type(_ArgTypes ...)> std::bind(_Functor, _ArgTypes ...) [with _Functor = void (A<void>::*)(), _ArgTypes = {A<void>}, typename std::_Maybe_wrap_member_pointer<_Tp>::type = std::_Mem_fn<void (A<void>::*)()>]' 
+2

"A 무효을"는 문자 "전자"처럼 부족, 불완전한 * 입력 체계 *입니다. (너무 모호한가요? http://en.wikipedia.org/wiki/A_Void) –

+0

@Steve LOL ... 유머 만이 코드를 컴파일하면 ... – HighCommander4

+0

예, 죄송합니다. 실제로 질문에 도움을 줄 수 없습니다. –

답변

4

주문이 잘못된 것입니다. 기본 템플릿에서 그것을

template <> 
class A<void> 
{  
    void f(); 
    typedef decltype(std::bind(&A::f, std::declval<A>())) some_type; 
}; 

교환을 시도, 이름 A::f이 의존하고 A가를 의미하기 때문에 f 선언 한 점에 컴파일러 지연 조회 (A::f는 더 이상 C + +0 정말 의존하지 않는 현재 구체화의 한 부분에 현재 인스턴스화와 그에 대한 f이 있지만 현재 스펙 (종속 기본 클래스와 관련이 있음)에 허점이 있기 때문에 컴파일러는 룩업을 지연합니다. 명시 적 전문화에서는 이름이 종속되지 않고 조회가 즉시 수행되므로 참조하기 전에 f을 선언해야합니다.

편집 :std::bind을 잘못 사용하고 있습니다. 두 번째 인수는 A<void> 유형이며, 생성 된 호출 래퍼 객체에 std::bind에 의해 복사/이동됩니다. 이 경우 완전한 유형 A<void>이 필요합니다.

멤버 함수가 호출 된 A에 대한 참조를 전달하려는 경우 std::bind 메커니즘이 멤버 포인터 호출에 대한 마법의 첫 번째 인수로 동등하게 검색하는 declval<A*>()을 전달할 수 있습니다.

하지만 및 decltype 엉망이 아닌 std::function<>을보고 싶은 것 같습니다. 결국 당신은 강력한 도구 세트를 가지고 있지만,이 의심스러운 decltype 표현식을 사용하면 표준 라이브러리가 제공하는 모든 일반성을 버리고 그 단일 std::bind 표현의 사용을 제한 할 수 있습니다. 그건 좋지 않아.

+0

도움이되지 않는 것 같습니다 : http : // ideone.com/IaKNM – Suma

+0

그래도 문제가 해결되지는 않지만 오류는 약간 달라집니다 (질문 편집 참조) – HighCommander4

+1

OK. 나는 그것을 알고 있다고 생각한다. 요하네스는 정확합니다.이 문제를 해결 한 후에 또 다른 문제가 드러납니다. VS가 2 단계 조회를 구현하지 않았기 때문에 VS 2010을 사용한 내 실험에이 문제가 표시되지 않으므로 두 번째 문제 만 표시됩니다. – Suma

2

std :: bind에는 A가 완전한 유형 (요하네스의 답변 참조)이 필요하므로이 시점에서 사용할 수 없습니다. 당신이 some_type이 will compile 캡슐화 경우이 문제를 해결 :

#include <functional> 

template <typename T> 
class A 
{ 
    void f(); 
    struct some_type_helper 
    { 
    typedef decltype(std::bind(&A::f, std::declval<A>())) some_type; 
    }; 
}; 

template <> 
class A<void> 
{ 
    void f(); 
    struct some_type_helper; 
}; 

struct A<void>::some_type_helper 
{ 
    typedef decltype(std::bind(&A::f, std::declval<A>())) some_type; 
}; 
+0

좋은 해결 방법 – HighCommander4

+0

예, 캡슐화는 때때로 유용 할 수 있습니다. 아직도,이 경우에는 Johannes가 제안한 것처럼 std :: declalk 을 사용하는 것이 더 쉽고 멋지다고 생각합니다. – Suma