C++/기타

[C++ Metaprogramming] enable_if / enable_if_t

sseram 2023. 3. 7. 21:47
반응형

C++11~

enable_if

 

C++17~

enable_if_t 

이건 사실 위의 enable_if 를 편히 쓸 수 있게 만들어 둔 것이다.

 

 

enable_if<?, ?>:: type 

enable_if_t<?, ?>

 

위 두개는 같은 표현이다 (C++ 17에서는)

 

 

 

 

<type_traits> 에 정의된 클래스 템플릿.

 

해당 템플릿을 통해

 

1. 특정한 상황일 때 불리는 overload 된 function을 만들 수 있거나,

2. 특정한 상황일 때 특정한 return type을 가지는 function을 만들 수 있다.

 

 

 

 

 

enable_if 정의는 아래와 같이 정의되어있다.

 

template <bool _Test, class _Ty = void>
struct enable_if {}; // no member "type" when !_Test

template <class _Ty>
struct enable_if<true, _Ty> { // type is _Ty for _Test
    using type = _Ty;
};

template <bool _Test, class _Ty = void>
using enable_if_t = typename enable_if<_Test, _Ty>::type;

 

 

 

enable_if 의 앞쪽 template에 들어가는 것이 true가 되면, type이 뒤에 오는 template으로 정의가 된다.

enable_if 의 앞쪽 template에 들어가는 것이 false가 되면, type이 정의되지 않는다.

 

이 부분에서 결국 중요한건 type 이 정의되어 있느냐, 정의되어 있지 않느냐이다.

 

template으로 넘어온 앞의 것이 true이면 type이라는 using을 사용한다.

template으로 넘어온 앞의 것이 false이면 type이라는 using을 사용하지 않는다.

 

 

그래서 type을 사용하려고 할 때, 앞에가 true인지 false인지에 따라 빌드되는게 달라진다.

 

 

예제를 보자.

 

 

 

#include <iostream>
#include <type_traits>

template <typename T>
typename std::enable_if_t<std::is_same_v<T, int>, void>
print(T t)
{
    std::cout << "print : " << t << std::endl;
}

int main()
{
    print(42);
    print("Hello, world!");  // 컴파일 에러!
    return 0;
}

 

main을 확인해 보자.

 

print(42) - > arg == int

print("Hello, world!") -> arg == const char* 

 

이런 식으로, print에 int 를 주거나 const char* 를 주고 있다.

 

 

print를 확인해 보자.

 

return type은

typename std::enable_if_t<std::is_same_v<T, int>, void> 이다.

 

먼저 enable_if_t 안을 확인하면

std::is_same_v<T, int>, void> 이다.

 

T가 만약 int라면 std::is_same_v<T, int> 가 true일 것이고,

int가 아니라면 false일 것이다.

 

 

그렇다면 int 를 넘겨주는 print는 

typename std::enable_if_t<true, void>

 

const char*을 넘겨주는 print는 

typename std::enable_if_t<false, void>

 

일 것이다.

 

근데 위에서 보면, 앞의 template 이 true인 것은 type이라는 using을 사용하지만,

false 인 것은 using을 사용하지 않는다. 즉 '없다'

 

 

결국,  해당 함수는 int parameter를 가진 것에 대해서만 만들어진다.

 

 

 

 

 

이 개념을 통하여, SFINAE를 편리하게 활용할 수 있다고 한다.

 

다만 위에서 봤듯이 코드가 좀 길어져서... C++ 20 이후부터는 concepts 라는 것을 활용한다고 하는데, 이건 또 공부해 봐야것다.

 

 

 

 

반응형

'C++ > 기타' 카테고리의 다른 글

[C++] DLL로 class export / import - 2  (0) 2023.03.20
[C++] DLL로 class export / import - 1  (0) 2023.03.16
[C++ String] string 나누기. string split  (0) 2023.03.04
[C++ keyword] noexcept  (0) 2023.03.02
[C++ keyword] explicit 란?  (4) 2023.02.25