2016-07-08 17 views
2

많은 질문과 답변을 읽었지만 this question은 내 눈을 가장 사로 잡았습니다. 그것과 그것의 해답은 도움이된다. 그러나 나는 아직도 내가 형식이 아닌 템플릿 인자를 사용하는 뒤에 사용법과 이론을 완전히 이해하지 못한다고 느낀다. 그것들은 사용되는 많은 유용한 예제를 제공하지만, 아무도 실제로 비 형식 템플릿 인자 뒤에있는 이론에 대해 밝히지는 않았다.왜 형식이 아닌 템플릿 인수가 사용됩니까?

예를 들어 구체적으로 알지는 못하지만보다 일반적인 이유는 정규 함수 인수가 아닌 형식이 아닌 템플릿 인수를 사용하는 이유입니다.

나는 그것이 컴파일 타임에 결정되고 모든 새로운 호출이 비 유형 템플릿 인자에 대해 결정된 값을 가진 새로운 함수를 생성한다는 것을 알고있다. 그렇다면 왜 함수에 원하는 매개 변수를 입력 할 수 있고 같은 결과를 가져올 수있을 때 같은 함수의 인스턴스를 여러 개 만들고 싶습니다. 컴파일 된 함수가 하나뿐입니다.

본질적으로 this page의 마지막 섹션에 따라 # 2 대신 # 1을 수행해야하는 이유는 무엇입니까? cplusplus.com?

# 1 :

template <class T, int N> 
T fixed_multiply (T val) 
{ 
    return val * N; 
} 

int main() { 
    std::cout << fixed_multiply<int,2>(10) << '\n'; 
    std::cout << fixed_multiply<int,3>(10) << '\n'; 
} 

# 2 : 또한

template <class T> 
T fixed_multiply (T val, int N) 
{ 
    return val * N; 
} 

int main() { 
    std::cout << fixed_multiply<int>(10, 2) << '\n'; 
    std::cout << fixed_multiply<int>(10, 3) << '\n'; 
} 

가 어떤 성능 이점 또는 둘 중 하나의 등이있을 것입니다? 형식이 아닌 템플릿 인수를 사용하여 이익을 얻을 수있는 일반적인 응용 프로그램이 있습니까? 아니면 특정 응용 프로그램에서 특정 결과를 산출하는 데 사용되는 매우 기술적 인 매개 변수입니까?

편집 : 이것은 몇 가지 이유로 복제본으로 표시되었으므로 첫 번째 단락에서 비슷한 질문에 대한 이유를 설명합니다.

+0

이제 벡터의 모든 요소에'std :: transform'을 사용하여 5를 곱합니다. –

+0

표시하는 예제에서는 차이점을 많이 만들지 않지만 두 값을 모두 비 형식 템플릿 인수로 만들면 큰 차이점은 템플릿 화 된 버전을 컴파일 타임에 평가되는'constexpr' 함수로 만들 수 있기 때문입니다. 형식이 아닌 템플릿 인수는 ['std :: array'] (http://en.cppreference.com/w/cpp/container/array) 또는 실제 배열을 얻기 위해 C 스타일 배열을 사용하는 함수에도 유용합니다 크기를 입력하고 런타임 인수로 크기를 전달할 필요가 없습니다. –

+2

@Amit 그 질문의 첫 번째 줄에 링크 된 것과 같은 질문입니다. – Barmar

답변

4

코드를 잘 유지하면서 컴파일러에서 특정 컴파일 타임 최적화를 원할 때 유용합니다. 나는 간단히 몇 가지 예를 나열합니다 :

지점 제거

void doSomething(bool flag) { 
    if (flag) { 
    //whatever 
    } 
} 

template <bool flag> 
void doSomething() { 
if (flag) { 
    //whatever 
} 

} 위의 예에서

, 당신은 doSomething를 호출 할 때 당신은 항상 컴파일시 flag의 가치를 알고있는 경우, doSomethingTruedoSomethingFalse 함수를 수동으로 작성하지 않고 분기 비용을 피할 수 있습니다. 많은 코드를 반복해야 할 수도 있습니다. 이 트릭은 예를 들어 네트워크 코드에서 send와 recv 사이의 코드를 고려할 때 유용하며 코드는 성능이 중요한 스택에 깊숙히 자리 잡고 있습니다. 그것은 중요한 루프 내에서 중단 된 경우, 상기 예에서

않도록 동적 메모리 관리

void someFunction(size_t size, float* inout) { 
    std::vector<float> tmp(size); 
    //do something with inout and tmp and then store result in inout 
} 

template <size_t N> 
void someFunction(float *inout) { 
    float tmp[N]; //or std::array if you like 
    //do something with inout and tmp and store result in inout 
} 

는 제 2 버전은 훨씬 더 잘 수행 할 것이다.컴파일러는 N이이에 해당하는 SIMD 명령으로 연산을 바꾸거나 할 수 있습니다, 4 또는 8임을 알고있는 경우

for (size_t i = 0; i < N; ++i) { 
    //some arithmetic 
} 

:

특별한 최적화

루프를 고려 허용 N이 런타임 인수 인 경우보다 지능적으로 루프를 언 롤하십시오. 이런 종류의 일은 GPU 프로그래밍 (CUDA) 세계에서 보편적입니다.

템플릿 메타 프로그래밍이 템플릿 일부 비 사소한 코드 생성을 수행 할 때 때때로 당신이 컴파일시에 일을 반복해야한다

. 이 작업을 수행하려면 템플릿이 아닌 인수를 사용해야합니다. 인수 팩과 std::tuple은 하나의 일반적인 경우이지만 여기에는 더 많은 것이 있으며 여기에 예시하기가 어렵습니다.

동적 매개 변수 (런타임)를 사용하는 코드의 유연성이 항상 높기 때문에 템플릿 매개 변수를 언제 선택해야하는지에 대한 질문에 대답하십시오. 상당한 성능 향상으로이를 정당화 할 수 있습니다. 반면에 열거 집합에 많은 중복 코드를 작성하는 경우 템플릿을 사용해보아야합니다.