개발/C++

함수 템플릿의 기본 템플릿 인수

MinorMan 2020. 9. 30. 22:32
반응형

<질문>

기본 템플릿 인수가 클래스 템플릿에서만 허용되는 이유는 무엇입니까? 멤버 함수 템플릿에서 기본 유형을 정의 할 수없는 이유는 무엇입니까? 예를 들면 :

struct mycclass {
  template
  void mymember(T* vec) {
    // ...
  }
};

대신 C ++에서는 기본 템플릿 인수가 클래스 템플릿에서만 허용되도록 강제합니다.


<답변1>

기본 템플릿 인수를 제공하는 것이 좋습니다. 예를 들어 정렬 함수를 만들 수 있습니다.

template::value_type> >
void sort(Iterator beg, Iterator end, Comp c = Comp()) {
  ...
}

C ++ 0x는이를 C ++에 도입합니다. Bjarne Stroustrup의이 결함 보고서 : 함수 템플릿에 대한 기본 템플릿 인수 및 그가 말하는 내용을 참조하십시오.

함수 템플릿에 대한 기본 템플릿 인수의 금지는 독립 함수가 2 급 시민으로 취급되고 모든 템플릿 인수가 지정되지 않고 함수 인수에서 추론되도록 요구했던 시대의 오해의 흔적입니다. 이 제한은 불필요하게 독립 함수를 멤버 함수와 다르게 만들어 프로그래밍 스타일을 심각하게 제한하므로 STL 스타일 코드를 작성하기가 더 어려워집니다.


<답변2>

C ++ 템플릿을 인용하려면 : 전체 가이드 (207 페이지) :

템플릿이 원래 C ++ 언어에 추가되었을 때 명시 적 함수 템플릿 인수는 유효한 구성이 아닙니다. 함수 템플릿 인수는 항상 호출 표현식에서 추론 할 수 있어야했습니다. 결과적으로 기본값은 항상 추론 된 값으로 재정의되기 때문에 기본 함수 템플릿 인수를 허용해야하는 설득력있는 이유가없는 것 같습니다.


<답변3>

지금까지 함수 템플릿에 대한 기본 템플릿 매개 변수의 모든 제안 된 예제는 오버로드로 수행 할 수 있습니다.

알코올:

struct S { 
    template  R get_me_R() { return R(); } 
};

다음과 같을 수 있습니다.

struct S {
    template  R get_me_R() { return R(); } 
    int get_me_R() { return int(); }
};

내 자신의:

template  int &increment(int &i) { i += N; return i; }

다음과 같을 수 있습니다.

template  int &increment(int &i) { i += N; return i; }
int &increment(int &i) { return increment<1>(i); }

litb :

template >
void sort(Iterator beg, Iterator end, Comp c = Comp())

다음과 같을 수 있습니다.

template
void sort(Iterator beg, Iterator end, std::less c = std::less())

template
void sort(Iterator beg, Iterator end, Comp c = Comp())

Stroustrup :

template 
void f(T t = 0, U u = 0);

다음과 같을 수 있습니다.

template  void f(S s = 0, T t = 0);
template  void f(S s = 0, double t = 0);

다음 코드로 증명했습니다.

#include 
#include 
#include 
#include 

template  T prettify(T t) { return t; }
std::string prettify(char c) { 
    std::stringstream ss;
    if (isprint((unsigned char)c)) {
        ss << "'" << c << "'";
    } else {
        ss << (int)c;
    }
    return ss.str();
}

template  void g(S s, T t){
    std::cout << "f<" << typeid(S).name() << "," << typeid(T).name()
        << ">(" << s << "," << prettify(t) << ")\n";
}


template  void f(S s = 0, T t = 0){
    g(s,t);
}

template  void f(S s = 0, double t = 0) {
    g(s, t);
}

int main() {
        f(1, 'c');         // f(1,'c')
        f(1);              // f(1,0)
//        f();               // error: T cannot be deduced
        f();          // f(0,0)
        f();     // f(0,0)
}

인쇄 된 출력은 f에 대한 각 호출의 주석과 일치하며 주석 처리 된 호출은 예상대로 컴파일되지 않습니다.

그래서 나는 기본 템플릿 매개 변수가 "필요하지 않다"고 생각하지만 아마도 기본 함수 인수가 "필요하지 않다"는 것과 같은 의미 일 것입니다. Stroustrup의 결함 보고서에서 알 수 있듯이 추론되지 않은 매개 변수를 추가하는 것은 너무 늦어서 기본값을 유용하게 만들었다는 사실을 누구든지 깨닫거나 감사하기에는 너무 늦었습니다. 따라서 현재 상황은 결코 표준이 아닌 기능 템플릿 버전을 기반으로합니다.


<답변4>

Windows에서는 모든 버전의 Visual Studio에서이 오류 (C4519)를 경고로 변환하거나 다음과 같이 비활성화 할 수 있습니다.

#ifdef  _MSC_VER
#pragma warning(1 : 4519) // convert error C4519 to warning
// #pragma warning(disable : 4519) // disable error C4519
#endif

여기에서 자세한 내용을 확인하세요.


<답변5>

내가 사용하는 것은 다음 트릭입니다.

다음과 같은 기능을 원한다고 가정 해 보겠습니다.

template  > void doStuff(ARR_E array)
{
    E one(1);
    array.add( one );
}

당신은 허용되지 않을 것이지만 다음 방법으로 수행합니다.

template 
struct MyArray_t {
void add(T i) 
{
    // ...
}
};

template  >
class worker {
public:
    /*static - as you wish */ ARR_E* parr_;
    void doStuff(); /* do not make this one static also, MSVC complains */
};

template 
void worker::doStuff()
{
    E one(1);
    parr_->add( one );
}

따라서 이렇게하면 다음과 같이 사용할 수 있습니다.

MyArray_t my_array;
worker w;
w.parr_ = &arr;
w.doStuff();

두 번째 매개 변수를 명시 적으로 설정할 필요가 없음을 알 수 있습니다. 누군가에게 유용 할 수도 있습니다.

반응형