비 유형 템플릿 매개 변수


93

비 유형 템플릿 매개 변수가 상수 정수 표현식이어야한다는 것을 이해합니다. 누군가가 왜 그렇게 밝힐 수 있습니까?

template <std::string temp>
void foo()
{
     // ...
}
error C2993: 'std::string' : illegal type for non-type template parameter 'temp'.

나는 상수 적분 표현이 무엇인지 이해합니다. std::string위의 스 니펫 과 같이 상수가 아닌 유형을 허용하지 않는 이유는 무엇입니까 ?


17
템플릿 매개 변수는 컴파일 타임에 확인됩니다.
Etienne de Martel 2011

답변:


121

이렇게 할 수없는 이유는 컴파일 타임 동안 상수가 아닌 식을 구문 분석하고 대체 할 수 없기 때문입니다. 런타임 중에 변경 될 수 있으며 런타임 중에 새 템플릿을 생성해야합니다. 템플릿은 컴파일 시간 개념이므로 불가능합니다.

표준에서 비 유형 템플릿 매개 변수 (14.1 [temp.param] p4)를 허용하는 것은 다음과 같습니다.

유형이 아닌 템플릿 매개 변수는 다음 (선택적으로 cv-qualified) 유형 중 하나를 가져야합니다.

  • 정수 또는 열거 유형,
  • 객체에 대한 포인터 또는 함수에 대한 포인터,
  • 객체에 대한 lvalue 참조 또는 함수에 대한 lvalue 참조,
  • 멤버에 대한 포인터,
  • std::nullptr_t.

6
@ALOToverflow : "회원에 대한 포인터"에 해당합니다. "멤버 함수에 대한 포인터"또는 "멤버 데이터에 대한 포인터"입니다.
Xeo 2013

4
개체 (또는 인스턴스 필드)에 대한 포인터의 경우 개체에 정적 저장 기간 및 연결 (외부 C ++ 11 이전, C ++ 11의 내부 또는 외부)이 있어야합니다. 컴파일 타임에 생성됩니다.
Theodore Murdock

2
C ++ 20에서는 형식이 구조화 된 동등성이 강하고 리터럴이고 변경 가능 / 휘발성 하위 개체가없고 우주선 연산자가 공용 인 경우에 허용됩니다.
Rakete1111

73

그것은 허용되지 않습니다.

그러나 다음은 허용됩니다.

template <std::string * temp> //pointer to object
void f();

template <std::string & temp> //reference to object
void g();

C ++ Standard (2003)의 §14.1 / 6,7,8을 참조하세요.


삽화:

template <std::string * temp> //pointer to object
void f()
{
   cout << *temp << endl;
}

template <std::string & temp> //reference to object
void g()
{
     cout << temp << endl;
     temp += "...appended some string";
}

std::string s; //must not be local as it must have external linkage!

int main() {
        s = "can assign values locally";
        f<&s>();
        g<s>();
        cout << s << endl;
        return 0;
}

산출:

can assign values locally
can assign values locally
can assign values locally...appended some string

7
@Mahesh : 템플릿의 기본 템플릿은 해당 std::string포인터 또는 참조 개체 의 주소이기 때문 입니다. 해당 변수가 로컬이면 함수가 호출 될 때마다 다른 주소를 얻을 수 있습니다.
Xeo 2011

11
@Mahesh : 컴파일 타임에 콜 스택이 어떻게 생겼는지 모릅니다. 함수 이전에 10 개 또는 3 개 또는 기타 여러 개가 호출되었을 수 있으므로 문자열이 생성되는 스택의 주소는 호출마다 변경 될 수 있습니다. 외부 연결이있는 개체가있는 경우 해당 주소는 컴파일 / 연결 중에 고정됩니다.
Xeo 2011

2
@Xeo " 해당 주소는 컴파일 / 연결 중에 고정됩니다. "또는 재배치 가능하거나 위치 독립적 인 코드의 경우.
curiousguy

1
이 답변은 (현재) 요청 된 OP의 질문을 해결하기 위해 보이지 않는 이유는 이 문제가 존재를; 이 답변은 설명을 제공하지 않고 OP의 예를 다시 설명합니다.
Quuxplusone

1
내가 늦게 파티 해요, 스마트 포인터도없는 일을 할 것 같다
니콜라스 험프리

28

템플릿 인수를 조작 할 수 있어야합니다.

template <std::string temp>
void f() {
 // ...
}

f<"foo">();
f<"bar">(); // different function!?

이제 impl은 std::string구현에 알려지지 않은 특정 값을 저장하는 임의의 다른 사용자 정의 클래스에 대해 고유 한 문자 시퀀스를 만들어야합니다. 또한 임의의 클래스 개체의 값은 컴파일 타임에 계산할 수 없습니다.

상수 표현식으로 초기화되는 C ++ 0x 이후의 템플릿 매개 변수 유형으로 리터럴 클래스 유형을 허용하는 것을 고려할 계획입니다. 데이터 멤버를 값에 따라 재귀 적으로 엉망으로 만들면 엉망이 될 수 있습니다 (예를 들어 깊이 우선, 왼쪽에서 오른쪽 순회을 적용 할 수있는 기본 클래스의 경우). 그러나 임의의 클래스에서는 작동하지 않을 것입니다.


10

템플릿 인수 목록 내에서 제공되는 유형이 아닌 템플릿 인수는 컴파일 타임에 값을 결정할 수있는 표현식입니다. 이러한 인수는 다음과 같아야합니다.

상수 표현식, 외부 링크가있는 함수 또는 객체의 주소 또는 정적 클래스 멤버의 주소.

또한 문자열 리터럴은 내부 연결이있는 개체이므로 템플릿 인수로 사용할 수 없습니다. 전역 포인터도 사용할 수 없습니다. 반올림 오류가 발생할 가능성이 분명하므로 부동 소수점 리터럴은 허용되지 않습니다.


인용문을 사용했는데 출처는 무엇입니까? 견적에 대한 출처가 있으면 찬성하고 싶습니다.
Gabriel Staples
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.