2017-01-20 2 views
2

나는 지금까지 필요한 모든 것을 제공하는 멋지고 작은 jack-all-all 거래 유형을 가지고 있습니다.C++ 생성자 및 호출 모호성 해결

template <typename T> 
class Array 
{ 
    ... 

public: 
    int Data; // custom value 
    virtual void InitData() { Data = 0; } 

    Array(const Array& array); 
    template <typename U, typename = std::enable_if<std::is_same<U, T>::value, U>> Array(const Array<U>& array); 
    template <typename... Ts> Array(const Ts&... items); 

    void Add(const T& item); 
    template <typename... Ts> void Add(const T& item, const Ts&... rest); 
    void Add(const Array& array); 
} 

template <typename... Ts> Array(const Ts&... items);Array<T> array = { ... }을하고, 할당하고 {...} 초기화 목록을 반환 할 수 있습니다. 생성자 중 어느 것도 명시 적이 지 않기 때문에, 그것은 매우 편리하지만 또한 지금 당황하게 된 이유이기도합니다.

배열에 "합리적인"것을 추가하고 싶습니다.

using Curve = Array<float2>; 

class Poly : public Array<float2> { using Array::Array; void InitData() override { Data = 1; } }; 
class Curve2 : public Array<float2> { using Array::Array; void InitData() override { Data = 2; } }; 
class Curve3 : public Array<float2> { using Array::Array; void InitData() override { Data = 3; } }; 

위의 std::is_same<> 물건 구체적이고 같은 동일하지만 모든 곡선 처리 할 수 ​​있도록 : 내 주요 사용 사례는 바로 지금입니다 서로 다른 정도의 곡선 유형을, 모든 것이 정적으로 "잘입니다 타입이 "이므로, DrawCurve(const Curve&)과 같은 함수에서하는 모든 작업은 학위를 확인한 다음 적절한 조치를 취하는 것입니다. Curve은 Array의 멋진 별칭이며 Curve2 등은 학위 전문 분야입니다. 그것은 아주 잘 작동합니다.

커브 생성을 할 때 나는 일반적으로 곡선 객체를 가지고 있는데 여기에는 점 또는 곡선 세그먼트이 추가됩니다. 그래서 할 수 있도록하고 싶습니다 : 내가 추가 호출 할 때 추가()를 가지고 있기 때문에

Curve3 curve; 
curve.Add(float2()); // ambiguity 
curve.Add(Array<float2>()); 

불행하게도, 내가 여기 모호성을 얻을 중 하나 float2 또는 잘 작동하는 Array<float2>,하지만, 배열 암시 적 생성자 template <typename... Ts> Array(const Ts&...)이 있으며 이는 float2을 인수로 취할 수 있습니다. 내가

template <typename A, typename = std::enable_if<std::is_same<A, Array>::value, A>> 
void Add(const Array& array); 

처럼 명시 적 배열을 생성자를 만드는 시도했다 그러나 나는 등 float2하는 Curve3에서 새로운 변환 오류를 얻을하고 엉망이된다

Array::Add(float2()); // and 
Array::Add(Array<float2>(float2())); 

사이에 따라서 모호성이다.

내 희망은 템플릿이나 다른 C++ 제품의 깊이에 어딘가에 내가 필요한 바로 그 간단한 해결책이 있다는 것입니다. (예, 나는 AddItem() 및 :: AddArray() 메소드의 이름을 바꿀 수 있다는 것을 알고 있고, 문제는 잠시 후에 끝날 것입니다. 그러나 결국이 모든 것을 두 배로 늘리기를 원하기 때문에 이것을 원하지 않습니다. += 그리고 대부분의 단지를 사용합니다.

어떤 아이디어?

+0

[여기] (http://coliru.stacked-crooked.com/a/beaea40305a2119f)의 코드를 꽂으면 그 두 가지 사이에 ambuiguity가없는 것 같습니다 –

답변

3

을 매개 변수 팩이 하나 개 이상의 항목을 포함하고 해당 항목의 유형이 아닌 경우

template <typename... Ts> Array(const Ts&... items); 

만 사용하려는 관찰 Array 템플릿 인스턴스입니다. 매개 변수 팩이 비어 있으면 기본 생성자가되므로이 사례를 별도로 처리해 보겠습니다. 광고를 생성하고 필요한 경우 기본 생성자를 명시 적으로 정의하고 필요한 작업을 수행합니다. 이제 우리는이 유스 케이스에서 그 가능성을 제거하고 앞으로 나아갈 수 있습니다.

이 길에서 저를 입수하는 데, 당신이 여기에서하고 싶은 것은이 생성자를 사용하는 것입니다 만이 하나 개의 인수가있는 경우 :

template <typename T1, typename... Ts> Array(const T1 &t1, const Ts&... items); 

당신은 명시 적 t1을 사용하려면이 생성자를 수정해야 할 것이다, 기존 매개 변수 팩과 함께 사용됩니다. 그렇게 간단해야하지만 충분하지 않습니다. 여전히 모호함이 있습니다. T1이 Array이 아닌 경우에만이 생성자를 선택하려고합니다.

아마도 뭔가 복잡한 것을 생각해 내고 하나의 std::enable_if으로 채우고이 템플릿으로 밀어 넣는 방법이있을 것입니다. 첫 번째 템플릿 매개 변수가 Array, 유사하지 않은 경우에만이 생성자를 선택 SFINAE을 사용하려면이 생성자의 템플릿에 간단한 std::enable_if를 추가 한 후

template<typename T> class is_not_array : public std::true_type {}; 

template<typename T> 
class is_not_array<Array<T>> : public std::false_type {}; 

그리고 : 그러나 명확성, 단순성, 나는 도우미 클래스를 사용합니다 다른 생성자에서 이미 std::enable_if을 어떻게 사용하고 있는지 알려줍니다.

이렇게하면 모든 모호성이 해결됩니다. 이 생성자는이 도우미 클래스의 도움을 받아 Array이 아닌 하나 이상의 템플릿 매개 변수로만 선택해야합니다. Array 일 때이 생성자는 해석 할 수 없으며이 경우 다른 생성자로 이동합니다.

const T & 대신 템플릿에서 범용 참조를 사용하는 것이 좋습니다.

+0

감사합니다. 템플릿 메타 프로그래밍은 여전히 ​​매우 신비 스럽습니다. :) – Alex