C++ Template Basics
1. ν νλ¦Ώ λ§€κ°λ³μμ μ’ λ₯: νμ vs. λΉ-νμ
C++ ν νλ¦Ώμ λ κ°μ§ μ£Όμ μ’ λ₯μ λ§€κ°λ³μλ₯Ό νμ©ν©λλ€.
| μ’ λ₯ | ν€μλ | μ λ¬λλ κ² | μ¬μ© μμ |
|---|---|---|---|
| νμ λ§€κ°λ³μ (Type Parameter) | typename λλ class |
μμμ λ°μ΄ν° νμ
(int, std::string, μ¬μ©μ μ μ ν΄λμ€ λ±) |
template <typename T> |
| λΉ-νμ λ§€κ°λ³μ (Non-Type Parameter) | κΈ°λ³Έ νμ
(int, bool, size_t λ±) |
μ»΄νμΌ μκ°μ μλ €μ§ κ° (μμ) | template <int N> |
2. ν νλ¦Ώ λ§€κ°λ³μλ₯Ό μ μΈνλ λ€μν λ°©λ²
ν νλ¦Ώ λ§€κ°λ³μλ₯Ό μ μΈν λλ μ΄λ¦(Identifier)κ³Ό κΈ°λ³Έκ°(Default Value)μ μ 무μ λ°λΌ λ€μ― κ°μ§ μ£Όμ ν¨ν΄μ΄ λνλλ©°, κ°κ°μ μ¬μ© λͺ©μ μ΄ λ€λ¦ λλ€.
2.1. λΉ-νμ ν νλ¦Ώ λ§€κ°λ³μ (Non-Type Template Parameters)
μ΄ λ§€κ°λ³μλ€μ μ»΄νμΌ μκ°μ μλ €μ§ κ°(Value)μ ν νλ¦Ώμ μ λ¬ν©λλ€. (μ: λ°°μ΄ ν¬κΈ°, μμ νλκ·Έ λ±)
template <int N>
class A { int v{N}; }; // Nμ λ΄λΆμμ μ¬μ©
template <int N = 10>
class B { int v{N}; }; // Nμ λ΄λΆμμ μ¬μ©, κΈ°λ³Έκ° μ 곡
template <int = 10>
class C { int v{0}; }; // μ΄λ¦ μκ³ , κΈ°λ³Έκ°λ§ μ 곡 (SFINAE μ©)
template <int>
class D { int v{0}; }; // μ΄λ¦λ κΈ°λ³Έκ°λ μμ (νμ μΆ©μ‘± μ©)
template <int, int>
class E { int v{0}; }; // μ¬λ¬ κ°λ₯Ό λμ΄
int main()
{
A<10> a{};
B<> b{};
C<> c{};
D<10> d{};
E<10, 10> e{};
}
| ν΄λμ€ | μ μΈ (template <β¦>) | νΉμ§ λ° μν | νμ© μμ |
|---|---|---|---|
| A | template <int N> |
μ΄λ¦ μμ, κΈ°λ³Έκ° μμ. κ°μ₯ μΌλ°μ μΈ ννμ΄λ©°, μ λ¬λ κ°μ λ΄λΆ λ‘μ§μ μ¬μ©ν©λλ€. | std::array<int, 5>μ 5μ κ°μ΄ ν¬κΈ°λ₯Ό μ λ¬ν λ |
| B | template <int N = 10> |
μ΄λ¦ μμ, κΈ°λ³Έκ° μμ. μΈμκ° μμ κ²½μ° κΈ°λ³Έκ°μ μ¬μ©νμ¬ νΈμμ±μ λμ λλ€. | μ΅μ νλκ·Έκ° μλ ν νλ¦Ώ |
| C | template <int = 10> |
μ΄λ¦ μμ, κΈ°λ³Έκ° μμ. μ λ¬λ κ°μ μ¬μ©νμ§ μμΌλ©°, μΈμλ₯Ό μλ΅νκΈ° μν΄ κΈ°λ³Έκ°μ μ 곡ν©λλ€. std::enable_ifμ λ
Όλ¦¬ μ μ΄ κ²μ΄νΈ μν μ μν΄ μ¬μ©λ©λλ€. |
std::enable_ifλ₯Ό μ¬μ©ν ν¨μ μ€λ²λ‘λ© |
| D | template <int> |
μ΄λ¦ μμ, κΈ°λ³Έκ° μμ. μ λ¬λ κ°μ μ¬μ©νμ§ μμΌλ©°, μ€μ§ νμμ μΌλ‘ λ§€κ°λ³μκ° νλ νμν¨μ λνλ λλ€. | κ±°μ μ¬μ©λμ§ μμ (Aκ° λ λͺ νν¨) |
2.2. νμ ν νλ¦Ώ λ§€κ°λ³μ (Type Template Parameters)
μ΄ λ§€κ°λ³μλ€μ νμ
(Type)μ ν
νλ¦Ώμ μ λ¬ν©λλ€. (μ: int, float, μ¬μ©μ μ μ ꡬ쑰체 λ±)
template <typename T>
class A { T v{0}; }; // Tλ₯Ό λ΄λΆμμ μ¬μ©
template <typename T = int>
class B { T v{0}; }; // Tλ₯Ό λ΄λΆμμ μ¬μ©, κΈ°λ³Έκ° μ 곡
template <typename = int>
class C { int v{0}; }; // μ΄λ¦ μκ³ , κΈ°λ³Έκ°λ§ μ 곡 (SFINAE μ©)
template <typename>
class D { int v{0}; }; // μ΄λ¦λ κΈ°λ³Έκ°λ μμ (νμ μΆ©μ‘± μ©)
template <typename, typename>
class E { int v{0}; }; // μ¬λ¬ κ°λ₯Ό λμ΄
int main()
{
A<int> a{};
B<> b{};
C<> c{};
D<int> d{};
E<int, int> e{};
}
| ν΄λμ€ | μ μΈ (template <β¦>) | νΉμ§ λ° μν | νμ© μμ |
|---|---|---|---|
| A | template <typename T> |
μ΄λ¦ μμ, κΈ°λ³Έκ° μμ. κ°μ₯ μΌλ°μ μΈ ννμ΄λ©°, μ λ¬λ νμ μ λ΄λΆμμ μ¬μ©ν©λλ€. | std::vector<int>μ intμ κ°μ΄ 컨ν
μ΄λμ νμ
μ μ μν λ |
| B | template <typename T = int> |
μ΄λ¦ μμ, κΈ°λ³Έκ° μμ. μΈμκ° μμ κ²½μ° κΈ°λ³Έ νμ
(int)μ μ¬μ©νμ¬ νΈμμ±μ λμ
λλ€. |
std::mapμ κΈ°λ³Έ λΉκ΅μ(Compare = std::less<Key>) |
| C | template <typename = int> |
μ΄λ¦ μμ, κΈ°λ³Έκ° μμ. μ λ¬λ νμ
μ μ¬μ©νμ§ μμΌλ©°, μΈμλ₯Ό μλ΅νκΈ° μν΄ κΈ°λ³Έκ°μ μ 곡ν©λλ€. std::enable_ifμ ν΅μ¬ ν¨ν΄μ
λλ€. |
std::enable_ifλ₯Ό μ¬μ©ν ν¨μ μ€λ²λ‘λ© |
| D | template <typename> |
μ΄λ¦ μμ, κΈ°λ³Έκ° μμ. μ€μ§ νμμ μΌλ‘ νμ λ§€κ°λ³μκ° νλ νμν¨μ λνλ λλ€. | κ±°μ μ¬μ©λμ§ μμ |
3. ν΅μ¬ ν¨ν΄: std::enable_ifμ μ΄λ¦ μλ λ§€κ°λ³μ (Class C)
std::enable_ifλ ν
νλ¦Ώμ μΆκ° λ§€κ°λ³μ μμΉμ μ½μ
λμ΄, 쑰건μ λ°λΌ ν΄λΉ ν
νλ¦Ώμ μ ν ν보μμ μ μΈνλ λ°©μμΌλ‘ λμν©λλ€ (SFINAE).
3.1. ν¨ν΄ 1: νμ ν νλ¦Ώ λ§€κ°λ³μ μ¬μ© (Type Template Parameter)
μ΄ λ°©μμ μΆκ°μ μΈ νμ
λ§€κ°λ³μλ₯Ό μ μΈνκ³ , κ·Έ κΈ°λ³Έκ°μ std::enable_if_tμ κ²°κ³Όλ‘ μ€μ ν©λλ€.
#include <type_traits> // std::is_integral, std::enable_if_t
// Tκ° μ μνμΌ λλ§ μ΄ ν¨μκ° μ ν¨ν¨
template <typename T,
typename = std::enable_if_t<std::is_integral<T>::value, float> // (A)
>
void check_type_foo()
{
std::cout << "Pattern 1: Tλ μ μνμ
λλ€ (νμ
λ§€κ°λ³μ μ¬μ©)" << std::endl;
}
// μ¬μ© μμ
check_type_foo<int>(); // (A)κ° floatμΌλ‘ μΉνλμ΄ μ±κ³΅
// check_type_foo<float>(); // (A)κ° μΉν μ€ν¨(SFINAE)νμ¬ μ»΄νμΌ μλ¬
λμ μ리 λΆμ:
-
μ±κ³΅ μ (T = int):
std::enable_if_t<true, float>$\to$floatνμ μΌλ‘ μΉν.- μ΅μ’
ν
νλ¦Ώ μ μΈμ
template <typename T, typename = float>μ΄ λμ΄ μ ν¨ν Class C νμ ν¨ν΄μ΄ μμ±λ©λλ€.
- μ΅μ’
ν
νλ¦Ώ μ μΈμ
-
μ€ν¨ μ (T = float):
std::enable_if_t<false, float>$\to$typeλ©€λ²λ₯Ό μ°Ύμ μ μμ΄ μΉν μ€ν¨κ° λ°μνλ©°, μ΄ ν¨μλ μ»΄νμΌλ¬μ ν보 λͺ©λ‘μμ μ μΈλ©λλ€.
3.2. ν¨ν΄ 2: λΉ-νμ ν νλ¦Ώ λ§€κ°λ³μ μ¬μ© (Non-Type Template Parameter)
μ΄ λ°©μμ μΆκ°μ μΈ λΉ-νμ
λ§€κ°λ³μλ₯Ό μ μΈνκ³ , κ·Έ νμ
μ std::enable_if_tμ κ²°κ³Όλ‘ μ€μ νλ©° κΈ°λ³Έ κ°(= true)μ ν λΉν©λλ€
#include <type_traits> // std::is_integral, std::enable_if_t
// Tκ° μ μνμΌ λλ§ μ΄ ν¨μκ° μ ν¨ν¨
template <typename T,
std::enable_if_t<std::is_integral<T>::value, bool> = true // (B)
>
void check_type_bar()
{
std::cout << "Pattern 2: Tλ μ μνμ
λλ€ (λΉ-νμ
λ§€κ°λ³μ μ¬μ©)" << std::endl;
}
// μ¬μ© μμ
check_type_bar<long>(); // (B)κ° bool = trueλ‘ μΉνλμ΄ μ±κ³΅
// check_type_bar<double>(); // (B)κ° μΉν μ€ν¨(SFINAE)νμ¬ μ»΄νμΌ μλ¬
λμ μ리 λΆμ:
-
μ±κ³΅ μ (T = long):
std::enable_if_t<true, bool>$\to$boolνμ μΌλ‘ μΉν.- μ΅μ’
ν
νλ¦Ώ μ μΈμ
template <typename T, bool = true>μ΄ λλ©°, μ΄λ μ ν¨ν Class C λΉ-νμ ν¨ν΄μ΄ μμ±λ©λλ€.
- μ΅μ’
ν
νλ¦Ώ μ μΈμ
-
μ€ν¨ μ (T = double):
std::enable_if_t<false, bool>$\to$typeλ©€λ²λ₯Ό μ°Ύμ μ μμ΄ μΉν μ€ν¨κ° λ°μνλ©°, μ΄ ν¨μλ ν보 λͺ©λ‘μμ μ μΈλ©λλ€.
λ ν¨ν΄μ μ°¨μ΄μ λ° μ₯μ
| νΉμ§ | ν¨ν΄ 1: νμ λ§€κ°λ³μ (typename = β¦) | ν¨ν΄ 2: λΉ-νμ λ§€κ°λ³μ (Type = Value) |
|---|---|---|
| μ μΈ νν | νμ λ§€κ°λ³μμ κΈ°λ³Έκ°μ μ‘°μ | λΉ-νμ λ§€κ°λ³μμ νμ μ μ‘°μ |
| λ€μ€ μ€λ²λ‘λ | λμΌν νμ
μκ·Έλμ²λ‘ κ°μ£Όλμ΄ μ»΄νμΌ μ€λ₯ λ°μ (ν¨μ fooλ₯Ό λ λ² μ μΈνλ κ²½μ°) |
μλ‘ λ€λ₯Έ λΉ-νμ λ§€κ°λ³μ κΈ°λ³Έκ°μ κ°μ§ μ μμ΄ ν νλ¦Ώ μ€λ²λ‘λ©μ μ ν© |
| κ°λ μ± | λ¨μν¨ | Type = Value ννκ° μ½κ° 볡μ‘ν¨ |
Reference
https://leimao.github.io/blog/CPP-Enable-If/