모호한 과부하 템플릿 << std::endl; } template<typename T1> void

다음과 같은 템플릿 코드가 있습니다

#include <vector>
#include <array>
#include <iostream>

template<typename T1>
void foo(std::vector<T1> bar) {
    std::cout << "GENERIC" << std::endl;
}

template<typename T1>
void foo(std::vector<std::vector<T1>> bar) {
    std::cout << "SPECIFIC (vector)" << std::endl;
}

template<typename T1, int SIZE>
void foo(std::vector<std::array<T1, SIZE>> bar) {
    std::cout << "SPECIFIC (array)" << std::endl;
}

int main() {
    std::vector<std::vector<int>> a(2, std::vector<int> { 1, 2, 3});
    std::vector<std::array<int, 3>> b(2, std::array<int, 3> {4, 5, 6});

    foo(a);
    foo(b);
}

어떤 생산

SPECIFIC (vector)
GENERIC

벡터 버전이 특정 템플릿으로 호출되는 이유가 궁금하지만 배열 벡터 버전이 일반으로 호출되는 이유는 무엇입니까?



답변

template<typename T1, size_t SIZE>
void foo(std::vector<std::array<T1, SIZE>> bar) {
    std::cout << "SPECIFIC (array)" << std::endl;
}

std::size_t대신 사용해야 합니다 int.
여기로 달려

편집 :
실제로, 귀하의 의견과 코드에 대한 나의 직감으로 인해 주제를 파헤 쳤습니다. 언뜻보기에, 표준 개발자 (나 같은)는 컴파일러 intstd::size_t(완전한 유형이고 암시 적으로 변환하는 것이 매우 간단하기 때문에 ) 컴파일러가 변환 void foo(std::vector<std::array<T1, SIZE>> bar)하고 최고의 전문화로 선택하기 를 기대합니다. 따라서 템플릿 인수 공제 페이지 를 읽는 동안 나는 이것을 발견했습니다.

비 유형 템플릿 매개 변수가 매개 변수 목록에 사용되고 해당 템플릿 인수가 추론되는 경우 추론 된 템플릿 인수의 유형 (포함 템플릿 매개 변수 목록에 지정된 참조는 유지됨)이 cv-qualifiers가 삭제되고 템플리트 인수가 배열 바운드에서 추론되는 경우를 제외하고는 형식이 아닌 템플리트 매개 변수가 정확합니다.이 경우 항상 일체형이 허용되지만 부울 한 유형도 허용됩니다.

항상 그렇듯이, 당신은 그것이 무엇을 의미하는지 이해하기 위해 몇 번 이상 읽어야합니다 🙂

흥미로운 결과가 나옵니다.

우리가 원하는 전문화는 이미 선택되어 있지 않지만 컴파일러가 강제로 선택했다면 오류가 발생합니다.

template<typename T1, int SIZE>
void foo(std::vector<std::array<T1, SIZE>> bar) {
    std::cout << "SPECIFIC (array)" << std::endl;
}

int main() {
    std::vector<std::array<int, 3>> b(2, std::array<int, 3> {4, 5, 6});

    foo(b); // P = std::vector<std::array<int,(int)SIZE>
            // A = std::vector<std::array<int,(unsigned_long)SIZE>>
            // error: deduced non-type template argument does not have the same
            // type as its corresponding template argument */
}

코드를 실행

또 다른 흥미로운 것은 :

비 타입 템플릿 인자가 추론되지 않았다면, 인자와 템플릿 타입을 동일하게 강제하는 제한은 없습니다.

#include <vector>
#include <array>
#include <iostream>

template<typename T1, int SIZE>
void foo(std::vector<std::array<T1, SIZE>> bar) {
    std::cout << "SPECIFIC (array)" << std::endl;
}

int main() {
    std::vector<std::array<int, 3>> b(2, std::array<int, 3> {4, 5, 6});

    foo<int,3>(b);
}

코드를 실행


답변

나는 이것이 단순히 한 줄 때문 이라고 생각 합니다.[temp.deduct.call]/4

일반적으로, 추론 프로세스는 추론 된 A를 A와 동일하게 만드는 템플리트 인수 값을 찾으려고 시도합니다.

명확히하기 위해 A매개 변수를 의미합니다.[temp.deduct.call]/1

… 호출의 해당 인수 유형으로 인수 공제를 고려하십시오 (A라고 부릅니다) …

이미 지적했듯이, 변경 하면 현재보고있는 문제 template<typename T1, int SIZE>template<typename T1, size_t SIZE>해결됩니다. 에서 언급했듯이 [temp.deduct.call]/4컴파일러는와 A동일한 것을 추론하려고 합니다 A. 이 때문에 std::array템플릿 인수가 <class T, size_t N>(에서 [array.syn]), 그것은 두 번째 매개 변수는 사실에의 size_t하지 int.

따라서 템플릿 공제의 경우 일반 함수는 의 유형 template<typename T1>정확하게 일치 할 수 있습니다 A. 여기서 특수한 함수 template<typename T1, int SIZE>정확히 일치 하지 않습니다 . MSVC의 추론이 틀렸다고 생각합니다.


답변