별도 컴파일, 유형 추출, 가변 매개변수 템플릿

분리 편집

  프로그램은 여러 소스 파일에 의해 공동으로 구현되고, 각 소스 파일은 개별적으로 컴파일되어 목적 파일을 생성하고, 마지막으로 모든 목적 파일을 연결하여 하나의 실행 파일을 형성하는 과정을 개별 컴파일 모드라고 합니다.템플릿은 별도의 컴파일을 지원하지 않습니다.

여기에 이미지 설명 삽입

  컴파일러에 의해 보고되는 이러한 종류의 오류는 링크 오류 즉, 프로그램이 전처리, 컴파일, 어셈블 및 링크될 때 링크 중에 오류가 발생합니다. 일반적으로 링크 오류는 함수가 선언되어 있지만 구현 본문이 작성되지 않았기 때문에 발생합니다. 따라서 프로그램이 링크되면 심볼 테이블에서 함수 이름만 발견되고 특정 함수 구현의 주소를 찾을 수 없으므로 컴파일러에서 이러한 오류를 보고합니다!
  여기서 다시 질문이 옵니다. 템플릿을 별도로 컴파일할 때 이러한 오류가 발생하는 이유는 무엇입니까?
  템플릿은 두 번 컴파일해야 합니다.
  첫 번째 컴파일은 인스턴스화 전입니다. 기본 문법 오류를 분석하는 데 사용되며 두
  번째 컴파일은 인스턴스화 후 형식을 대체한 후 문법 오류가 있는지 확인하는 데 사용됩니다.

요점은 여기에 있습니다! ! ! ! ! ! ! ! 우리 템플릿 코드의 구현체는 하나의 파일에 있고, 템플릿을 인스턴스화하기 위한 테스트 코드는 다른 파일에 있습니다.컴파일러는 하나의 파일을 컴파일할 때 다른 파일의 존재를 알지 못하므로 템플릿 코드는 인스턴스화 및 컴파일됨 컴파일러는 당연히 이에 대한 코드를 생성하지 않으므로 링커 오류가 발생합니다!

여기에 이미지 설명 삽입

따라서 위와 같은 문제를 해결해야 한다면 선언과 정의를 파일 "xxx.h"(헤더 파일)에 넣어야 합니다.

  

  

  

유형 추출

관련 정보:

C++ typeid 연산자: 유형 정보 가져오기

typeid 연산자는 표현식에 대한 유형 정보를 얻는 데 사용됩니다. 형식 정보는 프로그래밍 언어에 매우 중요하며 데이터의 다양한 속성을 설명합니다.

  • 기본 유형의 데이터(int, float 및 기타 C++ 내장 유형)의 경우 유형 정보에 포함된 내용은 주로 데이터 유형을 참조하는 비교적 단순합니다.
  • 클래스 타입 데이터(즉, 객체)의 경우 타입 정보는 객체가 속한 클래스, 포함하는 멤버, 상속 관계 등을 의미합니다.

타입 정보는 데이터를 생성하기 위한 템플릿이며, 데이터가 차지하는 메모리의 양, 어떤 연산을 수행할 수 있는지, 어떻게 연산할지 등은 모두 타입 정보에 의해 결정됩니다.

typeid의 작업 개체는 표현식 또는 데이터 유형일 수 있으며 다음 두 가지 사용 방법이 있습니다.
typeid( dataType ) typeid( expression )

dataType은 데이터 유형이고 expression은 sizeof 연산자와 매우 유사한 표현식입니다. 단, sizeof는 때때로 괄호를 생략할 수 ( )있지만 typeid는 괄호가 있어야 합니다.

#include <iostream>
#include <typeinfo>

using namespace std;

int main() {
    
    
    cout << typeid(int).name() << endl;  // i
    cout << typeid(1.0).name() << endl;  // d
    return 0;
}

문제 시나리오:

주어진 유형이 내장 유형인지 확인

솔루션: 상속 + 클래스 템플릿 특수화

#include <iostream>

using namespace std;

//TODO BEGIN
class yes {
    
    
public:
    static char* flag;
};
char* yes::flag = (char *)"yes";

class no {
    
    
public:
    static char* flag;
};
char* no::flag = (char *)"no";

class A {
    
    };
class B {
    
    };

template<typename T>
class type_trais : public no {
    
    };

template<>
class type_trais<int> : public yes {
    
    };

template<>
class type_trais<double> : public yes {
    
    };

template<>
class type_trais<int *> : public yes {
    
    };
//TODO END

#define TEST(type) \
    cout << #type << " : " << type_trais<type>::flag << endl;

int main() {
    
    
    TEST(int);
    TEST(A);
    TEST(double);
    TEST(B);
    TEST(string);
        TEST(int *);
    TEST(string *);
    return 0;
}
/*
int : no
A : yes
double : no
B : yes
string : yes
string * : no
*/

  

    

  

가변 함수 템플릿

//类似函数模板的偏特化,实则是一种重载形式
//函数模板没有偏特化   
//注意:而函数重载本质是函数,在使用之前必须有定义
template<typename T>           //递归出口
void Print(T a) {
    
    
    cout << a << endl;
    return ;
}

template<typename T, typename ...ARGS>
void Print(T a, ARGS... args) {
    
    
    cout << a << " | ";
    Print(args...);   //递归入口
    return ;
}

int main() {
    
    
    Print("hello world!", 666, 1.1, '$');
    Print("hello world!", 666, 1.1);
    Print("hello world!", 666);
    Print("hello world!");
    return 0;
}
/*
hello world! | 666 | 1.1 | $
hello world! | 666 | 1.1
hello world! | 666
hello world!
*/

추천

출처blog.csdn.net/qq_40342400/article/details/128511869