2012-11-02 2 views
3

이 질문은 (간접적으로) 표현 템플릿이 포함되어 있으므로 C++ 템플릿 메타 프로그래밍에 대한 지식이 필요합니다. 나는 직접적으로 표현 템플릿에 대한 질문이 아니기 때문에 간접적으로 말하지만 C++ 유형의 계산을 포함한다. 그것이 무엇인지 모르는 경우이 질문에 대답하지 마십시오.컴파일러에서 사용할 최종 형식 선택

충분한 배경 ​​지식없이 질문을하지 않으려면 내가 해결하려고하는 일반적인 문제에 대해 좀 더 자세하게 설명하고 더 구체적인 부분으로 이동하십시오.

사용자가 int과 같이 계산할 수있는 Integer을 제공하는 라이브러리가 있다고 가정합니다. int에서 Integer을 구성 할 수 있습니다. 그냥 좋아 :

template<class T> 
class Integer { 
    // cut out 
}; 

그래서 내가 원하는대로 정수 유형을 정의 할 수 있습니다 :

Integer<int> i(2); 

내부적 내 Integer 클래스는 클래스 템플릿입니다.

는 는

이제 API를 변경하지 않고, 내가 Integerint로 구성 된 경우는 다른 유형에 의해 내부적으로 표현되어야하는 방식으로 라이브러리를 변경하려면, IntegerLit을 을 말한다. 그 이유는 Integer의 인스턴스가 int (int 인수로 기본 포인터 + 개별 데이터로 설명 된 일반 개체 대신 함수에 전달 될 수 있음)에서 생성되었음을 알고 일부 계산 속도를 높일 수 있기 때문입니다. 단지 주석으로.)

내가 int 아닌지로 구성 여부에 따라 다른 코드 경로를 취하도록 컴파일러를 필요 때문에 int에서 구성 할 때 유형 다른 것이 필수적이다. 런타임 데이터 플래그로는이 작업을 수행 할 수 없습니다. (이유는 짧습니다 : 컴파일러는 int 또는 위에서 언급 한보다 일반적인 유형의 객체를 사용하는 함수를 생성합니다.

문제가 발생했다는 것을 알았습니다. 이 :

Integer<int> a,b(2); 

a = b + b; 

여기 a 일반 Integerb 전문 IntegerLit해야합니다. 그러나, 내 문제는 사용자가 자신의 변수를 정의하는 데 매우 동일한 유형 Integer을 자유롭게 사용할 수 있기 때문에이를 C++로 표현하는 방법입니다.

유형을 다형성으로 만드는 것, 즉 을 Integer에서 파생시키는 것은 작동하지 않습니다. 잠시 괜찮아 보인다. 그러나 기본 클래스이기 때문에 사용자가 Integer (기본 클래스)의 인스턴스를 작성하므로 컴파일러는 표현식 트리에 스틱을 붙입니다. (이것이 표현 템플릿이 질문에 포함 된 이유입니다.) 따라서 두 경우 모두 다시 구분할 수 없습니다. 라틴어로 RTTI 체크를하는 것은 내가 그 시점에서 원하는 것만은 아니다.

더욱 유망한 점은 int으로 구성된 경우 리터럴 템플릿 매개 변수 bool lit을 유형에 추가하는 것입니다. 요점은 리터럴이 아닌 변환 규칙을 지정하지 않고 다른 경우에 대해 지정하는 것입니다.

그러나 나는 그것을 작동시킬 수 없습니다. 다음 코드는 int에서 생성하지 않으면 (GCC 4.7 C++ 11) 만 컴파일합니다. 그렇지 않으면 정수가 true으로 지정되어 있지 않으므로 lit의 값으로 실패합니다. 따라서 컴파일러는 변환 규칙이없는 기본 구현을 검색합니다. int에서 생성 할 때 API를 변경하고 Integer<int,true>을 작성해야하는 옵션은 아닙니다.

template<class T,bool lit=false> 
class Integer 
{ 
public: 
    Integer() { 
    std::cout << __PRETTY_FUNCTION__ << "\n"; 
    } 
    T F; 
}; 

template<> 
template<class T> 
class Integer<T,true> 
{ 
public: 
    Integer(int i) { 
    std::cout << __PRETTY_FUNCTION__ << "\n"; 
    } 
    T F; 
}; 

저는 C++에서 이와 같은 것이 가능한지 궁금합니다.

여기서 도움이 될 수있는 C++ 11의 새로운 기능이 있습니까?

+0

'Integer'는 클래스 템플릿이고 객체를 만들기 위해서는 템플릿 인자가 필요하기 때문에 코드는 일반적으로 유효하지 않습니다. 'Integer a (2);'는 오류입니다. – Xeo

+0

맞아, 여기 간단 해. 실제로 사용자는'typedef'-ed 유형을 사용합니다.이 유형은 'Integer'와 with 및 int를 전문으로합니다. – ritter

+1

'int'로부터 생성하거나 정수 리터럴로부터 생성하는 것을 의미합니까? 중요한 차이가 있습니다. –

답변

5

아니요, 이것은 C++가 작동하는 방식이 아닙니다. bInteger b으로 정의하면 Integer입니다. 이는 b을 초기화하는 데 연속적으로 사용되는 식에 관계없이 적용됩니다.

또한 다음을 고려하십시오. extern Integer b;. b을 초기화하는 다른 표현식이 있지만 컴파일러는 여전히 여기에 어떤 유형 b이 있는지 파악해야합니다. ("가질 것"이 아니라 "가지고있다").

+0

'extern'은 좋은 지적입니다. 따라서 컴파일러가 어떤 유형의 생성자를 사용하는지 다른 유형을 사용하는 것은 C++에서는 불가능합니다. 그것이 당신이 말하는 것입니까? – ritter

+0

@Frank : 사용 가능한 생성자가 변수의 유형에 의존하므로 정확합니다. – Xeo

+0

@ Xeo : 또 다른 좋은 지적입니다.ctor를 선택하기 위해 과부하 해결을해야하지만, 그것은 당신이 이미'Integer' 클래스에 정착했다는 것을 전제로합니다. 'Integer b (5)'행을 구문 분석 할 때'b'가'Integer'를 리턴하는 함수인지'Integer' 타입의 새로운 변수인지 알아야합니다. 그것은'Integer' 부분에 대해 확실한 컴파일러를 위해 이미 복잡합니다. – MSalters

3

정확히 어쨌든 그렇게 할 수는 없습니다. 하지만 "자동"을 사용하면 가까이 올 수 있습니다.

// The default case 
Integer<int> MakeInt() 
{ 
    return Integer<int>(); 
} 

// The generic case 
template <class T> 
Integer<T> MakeInt(T n) 
{ 
    return Integer<T>(n); 
} 

// And specific to "int" 
Integer<IntegerLit> MakeInt(int n) 
{ 
    return Integer<IntegerLit>(n); 
} 

auto a = MakeInt(); 
auto b = MakeInt(2); 
auto c = MakeInt('c'); 
auto d = MakeInt(2.5); 
+0

+1, 비록 덜 편리하지만. –

1

당신은 그렇게 할 수 없습니다. 일단 변수가 Integer<int> 인 변수의 유형이라고 말한 경우 당신이 할 수는 Integer의 기본 담당자는, 생성자이 사용되는이 같은 것을 따라 다양 할 것입니다 수 있습니다

template<class T> 
class Integer { 
    // cut out 
    Integer() : rep_(IntRep()) {} 
    explicit Integer(int val) : rep_(IntLitRep(val)) {} 

private: 
    boost::variant<IntRep, IntLitRep> rep_; 
}; 

그런 다음 당신은 쉽게 활성화 된 변형 버전을 확인하고 다른 코드 경로를 이용할 수있다 필요 .

편집 :이 경우 Integer의 유형이 같더라도 템플릿 기능을 사용하여 rep가 효과적인 유형을 변경하므로 두 가지 유형으로 작동하는 것처럼 보일 수 있습니다.

+0

그래, 이건 내 경우에는 도움이 안돼. 당신이 말했습니다 : 내가하려고하는 것은 C++에서는 불가능합니다. – ritter

관련 문제