Moglobin's
article thumbnail

Overloads and templates - C++ Tutorials (cplusplus.com)

 

Overloads and templates - C++ Tutorials

1234567891011121314 // template arguments #include using namespace std; template T fixed_multiply (T val) { return val * N; } int main() { std::cout << fixed_multiply (10) << '\n'; std::cout << fixed_multiply (10) << '\n'; } 20 30

www.cplusplus.com

Overloaded functions

In C++, two different functions can have the same name if their parameters are different; either because they have a different number of parameters, or because any of their parameters are of a different type. For example:

C++에서, 두 개의 다른 함수는 각각의 변수가 다르면 같은 이름을 가질 수 있다; 변수의 개수가 다르거나, 변수의 데이터 타입이 다름에서의 이유 둘 다 가능하다. 예를 들어: 



In this example, there are two functions called operate, but one of them has two parameters of type int, while the other has them of type double. The compiler knows which one to call in each case by examining the types passed as arguments when the function is called. If it is called with two int arguments, it calls to the function that has two int parameters, and if it is called with two doubles, it calls the one with two doubles.

 

이 예제에서, 똑같이 operate라고 불리는 두 함수가 있다. 하지만 그 중 하나는 int 타입으로 두 변수를 갖고 있고, 다른 하나는 double 타입으로 변수들을 갖고 있다. 컴파일러는 함수가 호출되었을 때 전달되는 값의 타입을 인식하여 어떤 함수를 부를 지 구분한다. 만약 어떤 함수가 두 개의 int 값들과 함께 호출되었다면, 두 개의 int 변수를 가지고 있는 함수를 호출하고, 만약 두 개의 double 값과 함께 호출되었다면, 두 개의 double 변수를 가진 함수를 호출한다.


In this example, both functions have quite different behaviors, the int version multiplies its arguments, while the double version divides them. This is generally not a good idea. Two functions with the same name are generally expected to have -at least- a similar behavior, but this example demonstrates that is entirely possible for them not to. Two overloaded functions (i.e., two functions with the same name) have entirely different definitions; they are, for all purposes, different functions, that only happen to have the same name.

 

이 예제에서, 두 함수는 약간의 다른 기능을 한다. int 함수는 두 값을 곱하고, double 함수는 두 값을 나눈다. 이것은 일반적으로 그리 좋은 생각이 아니다. 두 개의 같은 이름을 가진 함수는 대체적으로 비슷한 연산이나 기능을 하는 역할이 기대된다. 하지만 이 예제는 전혀 그렇지 않아도 됨을 보여준다. 두 개의 오버로드 함수는 (i.e., 이름이 같은 두 함수) 완전히 다른 정의를 갖고 있다; 그들은 모든 의미에서, 다른 함수이고, 다만 어쩌다 같은 이름을 갖게 된 것 뿐이다.  


Note that a function cannot be overloaded only by its return type. At least one of its parameters must have a different type.

리턴 타입이 다른 것 만으로는 함수가 오버로드 될 수 없음을 기억하자. 적어도 하나의 변수는 다른 타입을 가져야 한다.

Function templates

Overloaded functions may have the same definition. For example:

오버로드 함수는 내용이 같을 수도 있다. 예를 들어:



Here, sum is overloaded with different parameter types, but with the exact same body.

여기서, sum은 다른 변수 타입으로 오버로드 되어있지만, 동일한 연산의 내용을 갖고 있다.

The function sum could be overloaded for a lot of types, and it could make sense for all of them to have the same body. For cases such as this, C++ has the ability to define functions with generic types, known as function templates. Defining a function template follows the same syntax as a regular function, except that it is preceded by the template keyword and a series of template parameters enclosed in angle-brackets <>:

 

함수 sum은 다양한 종류의 타입들로 오버로드 될 수 있고, 모두가 같은 바디를 갖는 것이 가능하다. 이러한 케이스들을 한꺼번에 처리할 수 있게, C++은 함수 템플릿이라는 제네릭 타입으로 함수를 정의할 수 있는 능력이 있다. 함수 템플릿을 정의하는 데에는 일반 함수와 같은 문법을 따르는데, 다만 해당 템플릿의 키워드와 각 브래킷 <>으로 감싸진 변수들이 선행된다:


template <template-parameters> function-declaration


The template parameters are a series of parameters separated by commas. These parameters can be generic template types by specifying either the class or typename keyword followed by an identifier. This identifier can then be used in the function declaration as if it was a regular type. For example, a generic sum function could be defined as:

템플릿 변수들은 쉼표로 구분되어 나열된다. 이 변수들은 클래스나 타입 이름 키워드로 명시하고 식별자를 뒤에 붙임으로써 제네릭 템플릿 타입이 될 수 있다. 이 식별자는 추후에 함수 정의 안에서 마치 일반 타입인 것처럼 사용될 수 있다. 예를 들어, 제네릭한 sum 함수는 다음과 같이 정의될 수 있다:

 


It makes no difference whether the generic type is specified with keyword class or keyword typename in the template argument list (they are 100% synonyms in template declarations).

 

여기 템플릿 변수에서 제네릭 타입을 클래스로 정의하든, 특정 타입으로 정의하든 아무 상관이 없다 (이들은 템플릿 선언에 있에 100% 동일어로 취급한다).  

In the code above, declaring SomeType (a generic type within the template parameters enclosed in angle-brackets) allows SomeType to be used anywhere in the function definition, just as any other type; it can be used as the type for parameters, as return type, or to declare new variables of this type. In all cases, it represents a generic type that will be determined on the moment the template is instantiated.

 

위의 코드에서, SomeType(각 브래킷 안에 들어있는 탬플릿 변수들의 제네릭 타입)을 선언하는 것은 SomeType가 여느 타입들처럼 함수 어디에서든 선언되어 사용될 수 있게 해준다. 변수의 타입으로도, 리턴 타입으로도, 또는 이 타입의 새로운 변수를 선언하는 데에도 사용 가능하다. 모든 케이스들에서, 템플릿이 선언되는 순간에 대표하는 제네릭 타입이 결정된다.


Instantiating a template is applying the template to create a function using particular types or values for its template parameters. This is done by calling the function template, with the same syntax as calling a regular function, but specifying the template arguments enclosed in angle brackets:

 

템플릿을 만드는 것은 해당 템플릿의 매개변수를 위한 타입이나 값을 사용하는 함수를 만들고 적용하기 위함이다. 이것은 function 템플릿을 호출함으로써 이루어지는데, 일반 함수를 호출하는 것과 같은 문법을 가진다. 하지만 템플릿의 인수들은 각괄호 속에 나열된다:


name <template-arguments> (function-arguments)
For example, the sum function template defined above can be called with:

템플릿명 <템플릿-인수> (함수-인수)

예를 들어, 위에 정의된 sum 함수 템플릿은 다음과 같이 호출될 수 있다:



The function sum<int> is just one of the possible instantiations of function template sum. In this case, by using int as template argument in the call, the compiler automatically instantiates a version of sum where each occurrence of SomeType is replaced by int, as if it was defined as:

함수 sum<int>는 함수 템플릿 sum의 가능한 여러 형태 중 하나이다. 이 경우에는 int를 템플릿의 매개변수로 사용함으로써, 컴파일러가 자동으로 SomeType가 int로 교체되는 것으로 작동하고, 다음 정의된 함수처럼 sum을 실행한다:



Let's see an actual example:

그럼 실제 예제를 한 번 보자:



In this case, we have used T as the template parameter name, instead of SomeType. It makes no difference, and T is actually a quite common template parameter name for generic types.

 

이 경우, 우리는 SomeType 대신 T를 템플릿의 매개변수로 사용하였다. 차이는 없지만, T는 제네릭 타입을 위한 매개변수의 이름을 정할 때 흔히 사용된다.

In the example above, we used the function template sum twice. The first time with arguments of type int, and the second one with arguments of type double. The compiler has instantiated and then called each time the appropriate version of the function.

 

위의 예제에서, 우리는 함수 템플릿 sum을 두 번 사용하였다. 첫번째는 int의 형식을 가진 인수와 함께, 그리고 두번째는  애 double의 형식을 가진 인수와 함께. 컴파일러는 각각 상황에 맞는 함수를 불러들였다.


Note also how T is also used to declare a local variable of that (generic) type within sum:

 

여기서 T는 sum 안에서의 지역변수를 선언하는데도 사용되었다는 점에도 주목하라:



Therefore, result will be a variable of the same type as the parameters a and b, and as the type returned by the function.

 

그러므로, 인수 a와 b와 같은 타입의 변수가 결과가 될 것이고, 이것은 함수가 리턴하는 타입과도 같다.


In this specific case where the generic type T is used as a parameter for sum, the compiler is even able to deduce the data type automatically without having to explicitly specify it within angle brackets. Therefore, instead of explicitly specifying the template arguments with:

이처럼 T가 sum의 인수로 사용되는 경우에는, 컴파일러는 각 브래킷이 없어도 자동으로 데이터 타입을 추정할 수 있다.

 

 



It is possible to instead simply write:

아니면 이렇게 쓰는 것도 가능하다:



without the type enclosed in angle brackets. Naturally, for that, the type shall be unambiguous. If sum is called with arguments of different types, the compiler may not be able to deduce the type of T automatically.

 

각 브래킷 없이 말이다. 이것을 이유로, 자연스럽게 모든 타입은 모호하지 않아야 한다. 만약 sum이 여러 종류의 타입의 인수들로 호출되었을 때, 컴파일러는 T의 타입을 자동으로 추정하지 못할 수도 있다.

Templates are a powerful and versatile feature. They can have multiple template parameters, and the function can still use regular non-templated types. For example:

템플릿은 강력하고 다재다능한 기능이다. 여러 개의 템플릿 매개변수들을 가질 수 있고, 함수는 계속 일반적인 타입들을 사용할 수 있다. 예를 들어: 

 



Note that this example uses automatic template parameter deduction in the call to are_equal:

이 예제는 are_equal을 부르기 위해 자동 매개변수 추정을 사용함을 알아두자:



Is equivalent to:

이것은 다음과 동일한 표현이다:



There is no ambiguity possible because numerical literals are always of a specific type: Unless otherwise specified with a suffix, integer literals always produce values of type int, and floating-point literals always produce values of type double. Therefore 10 has always type int and 10.0 has always type double.

여기서 가능한 모호함은 없는데 왜냐하면 숫자 상수들은 항상 어떤 타입으로 정의되어 있기 때문이다: 그것이 어떠한 접미사로 정의되지 않는 이상, 숫자 상수는 항상 int의 값을 배출하며, floating-point 상수들은 항상 double의 값을 배출한다. 그러므로 10은 항상 타입 int이고, 10.0은 항상 타입 double이다.

 

Non-type template arguments

The template parameters can not only include types introduced by class or typename, but can also include expressions of a particular type:

템플릿 매개변수들은 클래스나 타입이름뿐만 아니라, 특정 타입의 표현법도 설명할 수 있다.



The second argument of the fixed_multiply function template is of type int. It just looks like a regular function parameter, and can actually be used just like one.

 

fixed_multiply 함수 템플릿의 두번째 인수는 타입 int이다. 이것은 보통 일반적인 함수의 매개변수와 같이 생겼으며, 실제로 그렇게 사용될 수 있다.

But there exists a major difference: the value of template parameters is determined on compile-time to generate a different instantiation of the function fixed_multiply, and thus the value of that argument is never passed during runtime: The two calls to fixed_multiply in main essentially call two versions of the function: one that always multiplies by two, and one that always multiplies by three. For that same reason, the second template argument needs to be a constant expression (it cannot be passed a variable).

 

하지만 중요한 차이점이 존재하는데: 템플릿 매개변수의 값은 함수 fixed_multiply의 각 시행을 생성하는데 걸리는 컴파일 타임에 결정되고, 그러므로 해당 인수의 값은 런타임 도중에 절대 전달되지 않는다는 것이다. main 함수 안의  fixed_multiply의 두 호출은 사실상 두 가지 종류의 함수를 호출하는 것인데: 하나는 항상 2로 곱하는 것이고, 하나는 항상 3으로 곱하는 것이다. 똑같은 이유로, 두번째 템플릿 인수는 상수 표현으로 나타내져야 한다(변수로써 전달될 수 없다).

profile

Moglobin's

@슈플로프

Take your time 🍋