컨텍스트를 미워지는 기능 템플릿을 사용한 부분 순서
-
19-09-2019 - |
문제
또 다른 질문을 읽는 동안 부분 순서에 문제가 생겼습니다.
template<typename T>
struct Const { typedef void type; };
template<typename T>
void f(T, typename Const<T>::type*) { cout << "Const"; } // T1
template<typename T>
void f(T, void*) { cout << "void*"; } // T2
int main() {
// GCC chokes on f(0, 0) (not being able to match against T1)
void *p = 0;
f(0, p);
}
두 기능 템플릿의 경우 과부하 분해능을 입력하는 전문화의 기능 유형은 다음과 같습니다. void(int, void*)
. 그러나 부분 순서 (Comeau 및 GCC에 따르면)는 이제 두 번째 템플릿이 더 특화되어 있다고 말합니다. 하지만 왜?
부분 주문을 거쳐 질문이있는 곳을 보여 드리겠습니다. 5월 Q
에 따라 부분 순서를 결정하는 데 사용되는 고유 한 메이크업 유형입니다. 14.5.5.2
.
- 변환 된 매개 변수 목록
T1
(Q 삽입) :(Q, typename Const<Q>::type*)
. 논쟁의 유형은 다음과 같습니다AT
=(Q, void*)
- 변환 된 매개 변수 목록
T2
(Q 삽입) :BT
=(Q, void*)
, 또한 인수의 유형이기도합니다. - 변환되지 않은 매개 변수 목록
T1
:(T, typename Const<T>::type*)
- 변환되지 않은 매개 변수 목록
T2
:(T, void*)
C ++ 03은 이것을 지정하기 때문에 여러 결함 보고서에서 읽은 의도를 사용했습니다. 위의 변환 된 매개 변수 목록 T1
(라고 불리는 AT
나에 의해)는 인수 목록으로 사용됩니다 14.8.2.1
"함수 호출에서 템플릿 인수 추론".
14.8.2.1
변환 할 필요가 없습니다 AT
또는 BT
더 이상 자체 (예 : 참조 선언자 제거 등) 14.8.2.4
, 각각 독립적으로 A
/ P
쌍은 유형 공제를합니다.
AT
에 맞서T2
:{
(Q, T)
,
(void*, void*)
}
.T
여기에 유일한 템플릿 매개 변수이며T
해야합니다Q
. 유형 공제는 사소한 성공을 거두었습니다AT
에 맞서T2
.BT
에 맞서T1
:{
(Q, T)
,
(void*, typename Const<T>::type*)
}
. 그것은 그것을 찾을 것입니다T
~이다Q
, 여기도 여기.typename Const<T>::type*
비정상적인 맥락이므로 아무것도 추론하는 데 사용되지 않습니다.
여기 내 첫 번째 질문이 있습니다. T
첫 번째 매개 변수에 대해 추론 되었습니까? 대답이 아니오 인 경우 첫 번째 템플릿이 더 전문적입니다. GCC와 Comeau는 두 번째 템플릿이 더 특화되어 있다고 말하면서 그들이 틀렸다고 생각하지 않기 때문에 이것은 사실이 아닙니다. 그래서 우리는 "예"를 가정하고 삽입합니다 void*
~ 안으로 T
. 단락 (14.8.2.4
) 말한다 "공제는 각 쌍에 대해 독립적으로 수행되며 결과는 결합됩니다." 그리고 또한 "특정 상황에서는 값이 유형 공제에 참여하지 않고 대신 다른 곳에서 추론되거나 명시 적으로 지정된 템플릿 인수의 값을 사용합니다." 이것은 "예"처럼 들립니다.
따라서 모든 A / P 쌍에 대해 공제도 성공합니다. 이제 각 템플릿은 적어도 다른 템플릿만큼 전문화되어 있습니다. 공제는 암시 적 변환에 의존하지 않았고 양방향으로 성공했기 때문입니다. 결과적으로 호출은 모호해야합니다.
두 번째 질문 : 이제 구현에서 두 번째 템플릿이 더 전문적이라고 말하는 이유는 무엇입니까? 내가 간과 한 요점은 무엇입니까?
편집하다: 나는 최근의 GCC 버전에서 명시 적 전문화와 인스턴스화를 테스트했습니다.4.4
) 전문화에 대한 언급은 모호하며 이전 버전의 GCC (GCC) (4.1
) 모호성 오류가 발생하지 않습니다. 이는 최근 GCC 버전이 함수 템플릿에 대한 부분 순서가 일치하지 않음을 시사합니다.
template<typename T>
struct Const { typedef void type; };
template<typename T>
void f(T, typename Const<T>::type*) { cout << "Const"; } // T1
template<typename T>
void f(T, void*) { cout << "void*"; } // T2
template<> void f(int, void*) { }
// main.cpp:11: error: ambiguous template specialization
// 'f<>' for 'void f(int, void*)'
해결책
여기에 내가가요. 나는 동의한다 찰스 베일리 잘못된 단계는에서 나가는 것입니다 Const<Q>::Type*
에게 void*
template<typename T>
void f(T, typename Const<T>::type*) { cout << "Const"; } // T1
template<typename T>
void f(T, void*) { cout << "void*"; } // T2
우리가 취하고 싶은 단계는 다음과 같습니다.
14.5.5.2/2
두 개의 과부하 된 함수 템플릿이 주어지면, 하나는 다른 템플릿을 차례로 변환하고 인수 공제 (14.8.2)를 사용하여 다른 템플릿을 사용하여 결정할 수 있습니다.
14.5.5.2/3-b1
각각의 유형 템플릿 매개 변수에 대해, 고유 유형을 합성하고 함수 매개 변수 목록에서 해당 매개 변수의 각 발생 또는 템플릿 변환 함수에 대해 반환 유형에서 대체하십시오.
제 생각에는이 유형은 다음과 같이 합성됩니다.
(Q, Const<Q>::Type*) // Q1
(Q, void*) // Q2
나는 두 번째 합성 매개 변수를 요구하는 문구가 보이지 않습니다. T1
~이다 void*
. 나는 다른 맥락에서도 그에 대한 선례를 모른다. 유형 Const<Q>::Type*
C ++ 유형 시스템 내에서 완벽하게 유효한 유형입니다.
이제 우리는 공제 단계를 수행합니다.
Q2 ~ T1
우리는 T1의 템플릿 매개 변수를 추론하려고합니다.
- 매개 변수 1 :
T
추론됩니다Q
- 매개 변수 2 : 비정상적인 컨텍스트
파라미터 2는 추론되지 않은 맥락이지만, 우리는 T에 대한 가치가 있기 때문에 여전히 공제가 성공했습니다.
Q1 ~ T2
T2의 템플릿 매개 변수를 추론합니다.
- 매개 변수 1 :
T
추론됩니다Q
- 매개 변수 2 :
void*
일치하지 않습니다Const<Q>::Type*
그래서 공제 실패.
IMHO, 표준이 우리를 실망시키는 곳이 있습니다. 매개 변수는 의존적이지 않기 때문에 어떤 일이 일어날 지 명확하지 않지만 (14.8.2.1/3의 끈적 끈적한 읽기를 기반으로) 매개 변수 유형 p가 의존하지 않는 경우에도 인수 유형 A가 일치해야한다는 것입니다. 그것.
T1의 합성 된 인수는 T2를 전문화하는 데 사용될 수 있지만 그 반대도 마찬가지는 아닙니다. 따라서 T2는 T1보다 전문화되어 있으며 최상의 기능도 마찬가지입니다.
UPDATE 1:
포옹을 덮기 위해 Const<Q>::type
무효. 다음 예를 고려하십시오.
template<typename T>
struct Const;
template<typename T>
void f(T, typename Const<T>::type*) // T1
{ typedef typename T::TYPE1 TYPE; }
template<typename T>
void f(T, void*) // T2
{ typedef typename T::TYPE2 TYPE ; }
template<>
struct Const <int>
{
typedef void type;
};
template<>
struct Const <long>
{
typedef long type;
};
void bar ()
{
void * p = 0;
f (0, p);
}
위에서 Const<int>::type
일반적인 오버로드 해상도 규칙을 수행 할 때 사용되지만 부분 오버로드 규칙에 도달 할 때는 사용되지 않습니다. 임의의 전문화를 선택하는 것은 옳지 않습니다. Const<Q>::type
. 직관적이지는 않지만 컴파일러는 합성 된 형태의 형태를 갖는 것이 매우 기쁩니다. Const<Q>::type*
그리고 유형 공제 중에 사용합니다.
업데이트 2
template <typename T, int I>
class Const
{
public:
typedef typename Const<T, I-1>::type type;
};
template <typename T>
class Const <T, 0>
{
public:
typedef void type;
};
template<typename T, int I>
void f(T (&)[I], typename Const<T, I>::type*) // T1
{ typedef typename T::TYPE1 TYPE; }
template<typename T, int I>
void f(T (&)[I], void*) // T2
{ typedef typename T::TYPE2 TYPE ; }
void bar ()
{
int array[10];
void * p = 0;
f (array, p);
}
때 Const
템플릿은 일부 값으로 인스턴스화됩니다 I
, 그것은 재귀 적으로 스스로를 인스턴스화 할 때까지 I
0에 도달합니다. 이것은 부분 전문화시기입니다 Const<T,0>
선택됩니다. 기능의 매개 변수에 대한 실제 유형을 종합하는 컴파일러가있는 경우 컴파일러가 배열 인덱스에 어떤 값을 선택합니까? 10시? 글쎄, 이것은 위의 예에서는 괜찮지 만 부분 전문화와 일치하지 않습니다. Const<T, 10 + 1>
그것은 적어도 개념적으로, 1 차의 무한한 수의 재귀 적 인스턴스화를 초래할 것이다. 선택한 값이 무엇이든 우리는 최종 조건을 해당 값 + 1으로 수정할 수 있으며 부분 순서 알고리즘에 무한 루프가 있습니다.
부분 순서 알고리즘이 어떻게 인스턴스화 될 수 있는지 알 수 없습니다. Const
무엇을 찾기 위해 type
정말로.
다른 팁
편집 : 공부 후 클랜의 부분 순서 알고리즘의 구현 (Doug Gregor)에서, 나는 원래 예제가 모호하지 않은 나머지 포스터에 동의하게되었습니다. 그러한 상황에서 발생해야합니다. 나는이 게시물을 편집하여 수정 된 생각을 나타냅니다 (내 자신의 이익 및 참조). 특히 Clang의 알고리즘은typename Const<T>::type
'부분 순서 단계에서'void '로 번역되지 않으며 각 A/P 쌍은 서로 독립적으로 추론됩니다.
처음에 나는 왜 다음이 모호한 것으로 간주되는지 궁금했습니다.
template<class T> void f(T,T*); // 1
template<class T> void f(T, int*); // 2
f(0, (int*)0); // ambiguous
(The above is ambiguous because one cannot deduce f1(U1,U1*) from f2(T,int*), and going the other way, one cannot deduce f2(U2,int*) from f1(T,T*). Neither is more specialized.)
그러나 다음은 모호하지 않을 것입니다.
template<class T> struct X { typedef int type; };
template<class T> void f(T, typename X<T>::type*); // 3
template<class T> void f(T, int*); // 2
(모호 할 것으로 예상 할 수있는 이유는 다음과 같은 일이 발생했을 경우입니다.
- f3(U1,X<U1>::type*) -> f3(U1, int*) ==> f2(T,int*) (deduction ok, T=U1)
- f2(U2,int*) ==> f3(T, X<T>::type*) (deduction ok, T=U2 makes X<U2>::type* -> int*)
이것이 사실이라면 어느 쪽도 다른 것보다 더 전문적이지 않을 것입니다.)
Clang의 부분 순서 알고리즘을 연구 한 후에는 마치 마치 마치 마치 '3'을 다음과 같이 취급하는 것이 분명합니다.
template<class T, class S> void f(T, S*); // 4
따라서 'typename x :: type'에 대한 독특한 'u'의 공제는 성공합니다 -
f3(U1,X<U1>::type*) is treated as f3(U1, U2*) ==> f2(T,int*) (deduction not ok)
f2(U2,int*) ==> f3(T,S* [[X<T>::type*]]) (deduction ok, T=U2, S=int)
그래서 '2'는 '3'보다 분명히 더 특화되어 있습니다.
t1에 대한 변환 된 매개 변수-목록 (q 삽입) : (q, typeName const :: type*). 인수의 유형은 at = (q, void*)입니다.
그것이 실제로 올바른 단순화인지 궁금합니다. 유형을 합성 할 때 Q
, 당신은 Const
템플릿 종의 순서를 결정하기 위해?
template <>
struct Const<Q> { typedef int type; }
이것은 그것을 암시 할 것입니다 T2
적어도 전문화되지 않습니다 T1
a void*
매개 변수가 일치하지 않습니다 T1
주어진 템플릿 매개 변수에 대한 두 번째 매개 변수.
편집 :이 게시물을 무시하십시오 - Doug Gregor가 구현 한 부분 주문을위한 Clangs 알고리즘을 연구 한 후 (이 글을 쓰는 시점에서 부분적으로 구현 되었음에도 불구하고 OP의 질문과 관련된 논리가 충분히 구현 된 것 같습니다) - IT. 마치 미지의 컨텍스트를 다른 템플릿 매개 변수로 취급하는 것처럼 보입니다. 명백한 무효* 인수가있는 오버로드는보다 전문화 된 버전이어야하며 모호성이 없어야합니다. 평소와 같이 comeau는 정확합니다. 이제이 행동을 명확하게 정의하는 표준의 문구에 관해서는 또 다른 문제입니다 ...
이 게시물은 comp.lang.c ++에 게시되었으므로 중재하고 혼란을 일으키고있는 것 같습니다. 여기에 해당 그룹에 대한 답을 게시 할 것이라고 생각했습니다. .
On Jul 25, 1:11 pm, Bart van Ingen Schenau <b...@ingen.ddns.info> wrote:
You are going one step too fast here. How do you know (and would the compiler know) that there is no specialisation of Const<Q> such that Const<Q>::type != void?
As far as I can see, the compiler would transform the parameter-list of A to: AT=(Q, <unknown>*). To call B with these parameters requires an implicit conversion (<unknown>* to void*) and therefore A is less specialised than B.
나는 이것이 틀렸다고 믿는다. 어떤 함수가 더 특화되어 있는지 확인할 때 (부분 주문 중) 컴파일러는 매개 변수 목록을 다음으로 변환합니다. (Q, void*)
- 즉 실제로 관련 템플릿을 인스턴스화하고 (가장 잘 일치) '유형'의 값을 내부를 살펴 봅니다.이 경우 기본 템플릿을 기준으로 void*입니다.
부분 전문화에 관한 요점과 관련하여 - 템플릿이 다른 템플릿보다 더 전문화되는 것을 확인할 때, 사용할 수있는 유일한 유형은 고유 한 유형입니다. 끝났다) 그들은 고려 될 것이다. 나중에 추가하면 선택해야한다면 ODR을 위반하게됩니다 (14.7.4.1에 따라).
부분적/명시 적 전문화는 후보 세트를 형성하는 동안 고려를 얻을 것입니다. 그러나 이번에는 기능에 대한 실제 인수의 유형을 사용합니다. 가장 잘 어울리는 부분 전문화 (x)가 일부 매개 변수에 대해 더 나은 암시 적 변환 시퀀스를 갖는 함수 유형을 초래하면 부분 주문 단계로 만들지 않으며 "더 나은"기능이 선택됩니다 (만들기 전에 더 나은”기능이 선택됩니다. 부분 순서 단계에)
다음은 다양한 단계에서 무엇을 해야하는지에 대한 의견이있는 예입니다.
template<class T, bool=true> struct X; // Primary
template<class T> struct X<T,true> { typedef T type; }; // A
template<> struct X<int*,true> { typedef void* type; }; // B
template<class T> void f(T,typename X<T>::type); //1
template<class T> void f(T*,void*); //2
int main()
{
void* pv;
int* pi;
f(pi,pi);
// two candidate functions: f1<int*>(int*,void*), f2<int>(int*,void*)
// Note: specialization 'B' used to arrive at void* in f1
// neither has a better ICS than the other, so lets partially order
// transformed f1 is f1<U1>(U1,X<U1,true>::type) --> f1<U1>(U1,U1)
// (template 'A' used to get the second U1)
// obviously deduction will fail (U1,U1) -> (T*,void*)
// and also fails the other way (U2*, void*) -> (T,X<T>::type)
// can not partially order them - so ambiguity
f(pv,pv);
// two candidate functions: f1<void*>(void*,void*), f2<void>(void*,void*)
// Note: specialization 'A' used to arrive at second void* in f1
// neither has a better ICS than the other, so lets partially order
// transformed f1 is f1<U1>(U1,X<U1>::type) --> f1<U1>(U1,U1)
// (template 'A' used to get the second U1)
// obviously deduction will fail (U1,U1) -> (T*,void*)
// and also fails the other way (U2*, void*) -> (T,X<T>::type)
// can not partially order them - so ambiguity again
}
기본 템플릿에 정의가없는 경우 SFINAE가 부분 순서 단계에서 작동하며 다른 순서에서 추론 할 수 없으며 모호성이 발생해야한다는 점도 언급 할 가치가 있습니다.
또한 해당 함수 중 하나의 인스턴스화 지점이 번역 장치의 다른 곳으로 이동하면 다른 일치로 이어지는 다른 템플릿을 추가하면 ODR을 명확하게 위반하게됩니다.
On Jul 25, 1:11 pm, Bart van Ingen Schenau <b...@ingen.ddns.info> wrote:
첫째,보다 전문화된다는 것은 이것을 의미합니다 보다 적은 오버로드 해상도로 해당 템플릿을 선택할 수있는 유형. 이것을 사용하면 부분 순서 규칙을 다음과 같이 요약 할 수 있습니다. A를 호출 할 수 있지만 B를 호출하지 않거나 과부하 해상도가 A를 호출하는 것을 선호하는 A에 대한 유형을 찾으십시오. 해당 유형을 찾을 수 있다면 B가 더 특수화됩니다. A.보다
여기에 논쟁이 없습니다. 그러나 현재의 규칙에 따라 OP의 예는 모호해야합니다.
마지막으로, Litb가 제기 한 두 가지 특정 질문에 대한 명백하고 명백한 답변이 있습니다.
1) 이것은 이제 첫 번째 매개 변수에 대해 추론 된 t 값을 사용합니까?
예 - 물론, 템플릿 인수 공제를 수행하고 있습니다. '링크'를 유지해야합니다.
2) 이제 구현이 왜 두 번째가 더 전문적이라고 말합니까?
그들이 틀렸기 때문에;)
나는 이것이 문제를 해결하기를 바랍니다. 아직 확실하지 않은 것이 있는지 알려주세요 :)
편집 : Litb는 그의 의견에서 좋은 점을 제기했습니다. 아마도 기본 템플릿이 항상 고유 한 생성 된 유형의 인스턴스화에 사용될 것이라고 진술 할 것입니다.
기본 템플릿이 호출되지 않는 인스턴스가 있습니다.
내가 얻는 것은 부분 순서가 발생할 때 일부 고유 한 생성 유형이 최고의 전문화와 일치하는 데 사용된다는 것입니다. 맞습니다. 기본 템플릿 일 필요는 없습니다. 위의 언어를 편집했습니다. 그는 또한 인스턴스화 지점 후 더 나은 일치하는 템플릿을 정의하는 것과 관련하여 문제를 제기했습니다. 그것은 인스턴스화 시점의 섹션에 따라 ODR을 위반하는 것입니다.
표준에 따르면 A/P 쌍이 생성되면 (Temp.Func.Order에 설명 된대로 변환 규칙을 사용하여) 템플릿 인수 공제 (Temp.deduct)를 사용하여 서로에 대해 추론하고 해당 섹션이 사례를 처리한다고 말합니다. 템플릿과 그 중첩 유형을 인스턴스화하여 인스턴스화 지점을 트리거하지 않은 컨텍스트. Temp.Point 섹션은 ODR 위반을 처리합니다 (부분 순서의 의미는 번역 단위 내에서 인스턴스화 지점에 관계없이 변경되지 않아야합니다). 혼란이 어디에서 왔는지 아직도 모르겠습니다. - Faisal Vali 1 시간 전 [이 의견 삭제
LITB : "q를 const :: 유형에 넣는 단계는 sfinae 규칙에 의해 명시 적으로 다루어지지 않습니다. sfinae 규칙은 인수 공제와 함께 작동하고 q를 함수 템플릿 함수 매개 변수 목록에 넣는 단락을 넣습니다. 14.5.5.2에서. '
sfinae 규칙은 여기서 사용되어야합니다. 어떻게 할 수 없습니까? 나는 그것이 충분히 암시된다고 생각합니다. 나는 그것이 더 명확해질 수 있다는 것을 부정하지 않을 것이며,위원회가 이것을 명확히하도록 권장하지만, 당신의 예를 충분히 해석하기 위해 명확하게 할 필요는 없다고 생각합니다.
연결하는 한 가지 방법을 제공하겠습니다. (14.8.2) : "명시 적 템플릿 인수 목록이 지정된 경우 템플릿 인수는 템플릿 매개 변수 목록과 호환되어야하며 아래에 설명 된대로 유효한 기능 유형을 초래해야합니다. 그렇지 않으면 유형 공제 실패"
(14.5.5.2/3)에서 "사용 된 변환은 다음과 같습니다. - 각 유형 템플릿 매개 변수에 대해, 고유 유형을 합성하고 함수 매개 변수 목록에서 해당 매개 변수의 각 발생 또는 템플릿 변환 함수에 대해 반환하는 것을 대체합니다. 유형."
내 생각에 위의 인용문은 각 템플릿 매개 변수에 대해 "고유 한 생성 유형"을 "작성"하면 함수 선언이 명시 적으로 기능 템플릿에 템플릿 인수로 고유 유형을 제공합니다. 이로 인해 잘못된 함수 유형이 발생하면 변환뿐만 아니라 더 중요한 것은 기능을 부분적으로 주문하는 데 필요한 후속 템플릿 인수 공제가 실패합니다.
(14.5.5.2/4)에서 "변환 된 함수 매개 변수 목록을 사용하여 다른 함수 템플릿에 대한 인수 공제를 수행하십시오. 변환 된 템플릿은 최소한 다른 것만 큼 특화되어 있습니다. 경우에만, 공제가 성공하고 추론 된 매개 변수 유형은 정확히 일치합니다 (따라서 공제는 암시 적 변환에 의존하지 않습니다). "
변환 된 기능 매개 변수 목록이 대체 실패로 이어지면 공제가 성공할 수 없다는 것을 알고 있습니다. 그리고 공제는 성공하지 못했기 때문에 다른 것만 큼 전문화되지는 않습니다. 이것이 우리가 부분적으로 주문하기 위해 알아야 할 전부입니다.
LITB :이 경우에 어떤 일이 일어나는지 잘 모르겠습니다.
template<typename T> struct A;
template<typename T> void f(T, typename A<T>::type); template<typename T> void f(T*, typename A<T>::type);
확실히, 그것은 유효한 코드로 지출되지만 :: 유형을 수행하면 템플릿 정의 컨텍스트에서 아직 정의되지 않았기 때문에 "또한"이런 종류의 대체로 인한 템플릿 인스턴스화에 대해 정의 된 POI가 없기 때문에 실패합니다. 순서를 결정하려고하는 동안 (부분 순서는 컨텍스트에 의존하지 않습니다. 관련된 두 기능 템플릿의 정적 속성입니다). 나는 이것이 수정해야 할 표준의 문제처럼 보인다고 생각합니다.
OK - 우리가 어디에서 다르게보고 있는지보고 있다고 생각합니다. 내가 당신을 올바르게 이해한다면, 당신은 이러한 함수 템플릿이 선언 될 때, 컴파일러는 오버로드 해상도가 그들 사이에서 선택되도록 트리거되는 것에 관계없이 그들 사이의 부분 순서를 추적하고 있다고 말합니다. 그것이 당신이 그것을 해석하는 방법이라면, 나는 당신이 설명하는 위의 행동을 기대하는 이유를 알 수 있습니다. 그러나 나는 표준이 그것을 요구하거나 의무화한다고 생각하지 않습니다.
이제 표준은 부분 순서가 함수를 호출하는 데 사용되는 유형에 비해 불가지론이라는 것이 명백합니다 (정적 속성이라고 설명 할 때 말하면 컨텍스트 독립이라고 생각합니다).
표준은 또한 과부하 해상도 (13.3.3/1) 과정에서 기능 템플릿간에 부분 순서 (부분 순서를 호출)에만 관심이 있음을 분명히합니다. 템플릿이고 다른 하나는 아닙니다. [클래스 템플릿의 부분 순서 부분 순서 부분 전문화는 별도의 문제이며 내 마음에는 해당 특정 클래스의 인스턴스화가 필요한 관련 컨텍스트 (기타 템플릿 정의)를 사용합니다.
따라서 내 생각에, 과부하 해상도가 수행 될 때 기능 템플릿의 부분 순서 기계가 호출되므로 과부하 해상도가 수행되는 시점에서 사용할 수있는 컨텍스트 (템플릿 정의 및 전문화)의 관련 부분을 사용해야합니다. .
따라서 상호 작용에 따라 위의 'Template Struct a'를 사용하는 예에 따라 코드가 유효합니다. 부분 순서는 정의 컨텍스트에서 수행되지 않습니다. 그러나 F (int*) 0,0)에 대한 호출을 작성하여 두 기능간에 과부하 해상도를 호출 할 경우 - 컴파일러가 후보 선언을 조립하거나 부분적으로 주문할 때 ( 부분 주문 단계에 도달)) 잘못된 표현식 또는 유형의 결과가 함수 유형의 일부로 결과가 우리를 도와주고 템플릿 공제가 실패한다는 것을 알려줍니다 (부분 순서가 관련이있는 한, 더 이상 할 수 없음을 의미합니다. 템플릿을 변환 할 수 없다면 다른 것보다 전문화).
이제 POI와 관련하여 - 당신이 내가 확신한다면, 내가 확신한다면, 변환 된 함수 유형은 명시 적으로 제공된 템플릿 인수 목록 (고유하게 생성 된 유형 사용)을 사용하여 암시 적 인스턴스화를 나타 내기 위해 다음 표준 따옴표가 관련이 있습니다.
14.6.4.1/1 함수 템플릿 전문화, 멤버 함수 템플릿 전문화 또는 클래스 템플릿의 멤 그것이 참조되는 컨텍스트는 템플릿 매개 변수에 따라 다르며, 전문화의 인스턴스화 지점은 동봉 된 전문화의 인스턴스화 지점입니다.
내가 이것을 해석하는 방식은 변환 된 함수 유형의 POI와 Origianl 함수 유형이 실제 함수 호출에 의해 생성 된 함수의 POI와 동일하다는 것입니다.
LITB : 부분 순서는 오히려 단지 전용입니다
a property of the syntactic form of parameters (i.e "T*" against "T(*)[N]"),
나는 사양을 수정하기 위해 투표합니다 (예 : "Q가 유형을 명명 한 자격을 갖춘 이름 지정자로 표시되면"Q "라는 유형이 다른 유형이 다른 고유 유형이라고 말합니다.This means that in template<typename T> void f(T, typename Const<T>::type*);
the argument list is (Q, R*), for example.
Same for template<typename T> void f(T*, typename ConstI<sizeof(T)>::type);
the arg lisst would be (Q*, R). A similar rule would be needed for non-type parameters, of course.
그래도이 문제에 대해 생각하고 몇 가지 테스트 사례를 만들어 자연 순서를 산출 할 것인지 확인해야합니다.
AAH- 이제 당신은 우리 모두가 직관적으로 기대하는 것에 찬성하여 모호성을 해결하는 가능한 솔루션을 제안하고 있습니다. 이것은 별도의 문제입니다. 그리고 당신이 향하는 방향을 좋아하지만, 나는 또한 생각을해야 할 것입니다. 그것의 효과를 선포하기 전에 그것에.
토론을 계속 해주셔서 감사합니다. 나는 당신이 댓글을 작성하는 데 제한하지 않기를 바랍니다.
내 게시물을 편집 할 수 있으므로 더 쉬운 경우 게시물 내에서 자유롭게 응답하십시오.