템플릿의 특정 전문화 금지

기본적인 수치 계산을 수행하는 간단한 템플릿 함수를 상상해 봅시다.

template <typename T>
T f(T t) {
    return 2 * t + 3;
}


이 기능에는 문제가 없어 보입니다. 여러 유형에서 사용할 수 있습니다. f(15)는 33을 반환하고 Tint, f(2.3)는 7.6을 반환하고 Tdouble 등입니다. T 가 덧셈을 지원하는 유형이 아닌 경우 곱하면 컴파일러 오류가 발생합니다. f("hello")의 예:

error: invalid operands to binary expression ('int' and 'const char *')



그럼에도 불구하고 계획하지 않은 경우가 발생할 수 있습니다. 예를 들어, f(true)는 유효하고 경고를 발생시키지 않으며 true를 반환합니다(사실, 부울로 변환된 5, 즉 true)를 반환합니다.

컴파일 타임에 거부f<bool>하는 방법을 시도해 보겠습니다. 템플릿의 특정 전문화를 금지하는 가능성이 C++ 버전과 함께 발전했음을 알 수 있습니다. 각 기술에 대해 컴파일러 clangf(true) 에 대해 생성하는 오류를 보여드리겠습니다.

여기서 내 목적은 덧셈과 곱셈을 지원하지 않는 유형을 적절하게 처리하는 것이 아니라 특정 전문화를 금지하는 것입니다.

=전문화 시 삭제



C++11부터

첫 번째 해결책은 f()에 대한 T == bool의 전문화를 명시적으로 삭제하는 것입니다.

template<>
bool f(bool) = delete;


error: call to deleted function 'f'

note: candidate function [with T = bool] has been implicitly deleted



static_assert



두 번째 솔루션은 Tf() 에 정적 어설션을 추가하는 것입니다. static_assert는 C++11에 도입되었습니다. 표준 라이브러리에는 Tbool가 아닌지 확인하는 두 가지 기술이 있습니다. 하나는 C++11이고 다른 하나는 C++17입니다.

C++11부터

C++11이 도입되었습니다the template structure std::is_same , 이는 여러분이 생각하는 것과 정확히 일치합니다.

#include <type_traits>

template <typename T>
T f(T t) {
    static_assert(not std::is_same<T, bool>::value, "T cannot be bool");
    return 2 * t + 3;
}


error: static_assert failed due to requirement '!std::is_same<bool, bool>::value' "T cannot be bool"



C++17부터

C++17은 변수 템플릿std::is_same_v<U, V>std::is_same<U, V>::value 의 바로 가기로 도입했습니다.

#include <type_traits>

template <typename T>
T f(T t) {
    static_assert(not std::is_same_v<T, bool>, "T cannot be bool");
    return 2 * t + 3;
}


error: static_assert failed due to requirement '!std::is_same_v<bool, bool>' "T cannot be bool"



참고: variable templates were introduced in C++14 .

개념



C++20부터

Concepts은 C++20의 가장 큰 특징 중 하나입니다. Tbool인 것을 금지하는 개념에는 두 가지 가능성이 있습니다.

require 절과 함께




#include <concepts>

template <typename T> requires (not std::same_as<T, bool>)
T f(T t) {
    return 2 * t + 3;
}


error: no matching function for call to 'f'

note: candidate template ignored: constraints not satisfied [with T = bool]

note: because '!std::same_as<_Bool, _Bool>' evaluated to false



커스텀 컨셉으로




#include <concepts>

template <typename T, typename U>
concept different_than = not std::same_as<T, U>;

template <different_than<bool> T>
T f(T t) {
    return 2 * t + 3;
}


error: no matching function for call to 'f'

note: candidate template ignored: constraints not satisfied [with T = bool]

note: because 'different_than<_Bool, _Bool>' evaluated to false

note: because '!std::same_as<_Bool, _Bool>' evaluated to false



결론



제 생각에는 =delete 다른 기술에 비해 장점이 없습니다. 사용자 정의 오류 메시지를 작성할 수 있기 때문에 static_assert를 좋아하지만 하루가 끝나면 개념이 더 명확한 의미를 갖기 때문에 개념이 더 크다고 생각합니다. 그리고 그 정상: 템플릿 매개변수의 제약 조건을 정확히 표현하기 위해 만들어졌습니다.

👇🏻 어떤 기술을 사용/선호하는지, 그리고 그 이유를 댓글로 남겨주세요 😃

추신: 이 기사의 아이디어는 👍🏻의 토론에서 비롯되었습니다.

좋은 웹페이지 즐겨찾기