std :: decay는 무엇이며 언제 사용해야합니까?


185

존재하는 이유는 무엇입니까 std::decay? 어떤 상황에서 std::decay유용합니까?


3
스레드에 인수를 전달할 때와 같이 표준 라이브러리에서 사용됩니다. 그것들 은 값 으로 저장 되어야 하므로 예를 들어 배열을 저장할 수 없습니다. 대신 포인터가 저장됩니다. 기능 매개 변수 유형 조정을 모방하는 메타 기능이기도합니다.
dyp

3
decay_t<decltype(...)>auto추론 할 수 있는 좋은 조합 입니다.
Marc Glisse

58
방사성 변수? :)
saiarcot895

7
std :: decay ()는 세 가지 일을 할 수 있습니다. 1 T의 배열을 T *로 변환 할 수 있습니다. 2. cv 한정자와 참조를 제거 할 수 있습니다. 3. 기능 T를 T *로 변환합니다. 예 : 부패 (void (char))-> void (*) (char). 아무도 대답에서 세 번째 사용법을 언급하지 않은 것 같습니다.
r0ng

1
우리가 아직 C ++에서 쿼크를 가지고 있지 않다는 점에 감사합니다
Wormer

답변:


192

<joke> 방사성 std::atomic유형을 비 방사성 유형으로 붕괴시키는 데 사용됩니다 . </ joke>

N2609 는 제안한 논문이다 std::decay. 이 논문은 다음과 같이 설명합니다.

간단히 말해서, decay<T>::typeT가 배열 유형이거나 함수 유형에 대한 참조 인 경우를 제외하고 ID 유형 변환입니다. 이 경우 decay<T>::type함수에 대한 포인터 또는 포인터가 각각 생성됩니다.

동기 부여 예제는 C ++ 03입니다 std::make_pair.

template <class T1, class T2> 
inline pair<T1,T2> make_pair(T1 x, T2 y)
{ 
    return pair<T1,T2>(x, y); 
}

문자열 리터럴이 작동하도록하기 위해 값으로 매개 변수를 승인했습니다.

std::pair<std::string, int> p = make_pair("foo", 0);

참조로 매개 변수를 수락 T1하면 배열 유형으로 추론 된 다음 a 구성 pair<T1, T2>이 잘못됩니다.

그러나 분명히 이것은 비효율적 인 결과를 초래합니다. 따라서, 값별 decay전달이 발생할 때 발생하는 변환 세트를 적용하여 매개 변수를 참조로 효율적으로 사용할 수는 있지만 코드가 문자열 리터럴로 작동하는 데 필요한 유형 변환을 얻을 수 있어야합니다. 배열 유형, 함수 유형 등 :

template <class T1, class T2> 
inline pair< typename decay<T1>::type, typename decay<T2>::type > 
make_pair(T1&& x, T2&& y)
{ 
    return pair< typename decay<T1>::type, 
                 typename decay<T2>::type >(std::forward<T1>(x), 
                                            std::forward<T2>(y)); 
}

참고 : 이것은 실제 C ++ 11 make_pair구현 이 아닙니다 . C ++ 11 make_pairstd::reference_wrappers 를 풉니 다 .


"T1은 배열 유형으로 추론 된 다음 쌍 <T1, T2>를 구성하는 것은 잘못 구성됩니다." 여기서 무슨 문제가 있습니까?
camino

6
나는 그것을 얻는다. 이런 식으로 우리는 pair <char [4], int>를 얻을 것이다. 이것은 4 개의 문자로만 문자열을 받아 들일 수있다
camino

@camino 나는 그것을 얻지 못한다. std :: decay가 없으면 페어의 첫 번째 부분은 char에 대한 하나의 포인터 대신 4 개의 문자에 대해 4 바이트를 차지한다고 말하고 있습니까? 이것이 std :: forward가하는 일입니까? 배열에서 포인터로 붕괴되는 것을 막습니까?
Zebrafish

3
@Zebrafish 배열 붕괴입니다. 예를 들면 다음과 같습니다. template <typename T> void f (T &); f ( "abc"); T는 char (&) [4]이지만 template <typename T> void f (T); f ( "abc"); T는 char *이며; 또한 여기서 설명을 찾을 수 있습니다 : stackoverflow.com/questions/7797839/…
camino

69

템플릿 유형의 매개 변수를 사용하는 템플릿 함수를 처리 할 때 일반적으로 범용 매개 변수가 있습니다. 범용 매개 변수는 거의 항상 한 종류 또는 다른 종류의 참조입니다. 그들은 또한 const-volatile 자격을 갖추고 있습니다. 따라서 대부분의 유형 특성은 예상대로 작동하지 않습니다.

template<class T>
void func(T&& param) {
    if (std::is_same<T,int>::value) 
        std::cout << "param is an int\n";
    else 
        std::cout << "param is not an int\n";
}

int main() {
    int three = 3;
    func(three);  //prints "param is not an int"!!!!
}

http://coliru.stacked-crooked.com/a/24476e60bd906bed

해결책은 다음과 std::decay같습니다.

template<class T>
void func(T&& param) {
    if (std::is_same<typename std::decay<T>::type,int>::value) 
        std::cout << "param is an int\n";
    else 
        std::cout << "param is not an int\n";
}

http://coliru.stacked-crooked.com/a/8cbd0119a28a18bd


14
나는 이것에 만족하지 않습니다. decay예를 들어 배열에 대한 참조에 적용되면 포인터가 생성됩니다. 이러한 종류의 메타 프로그래밍 IMHO에는 일반적으로 너무 공격적입니다.
dyp

@dyp, 그렇다면 덜 "공격적"인 것은 무엇입니까? 대안은 무엇입니까?
Serge Rogatch

5
@SergeRogatch "유니버설 매개 변수"/ 범용 참조 / 전달 참조의 remove_const_t< remove_reference_t<T> >경우 사용자 지정 메타 함수로 래핑됩니다.
dyp

1
param은 어디에 사용 되나요? 그것은 func의 논쟁이지만 어디에서나 사용되는 것을 보지 못합니다
savram

2
@savram :이 코드에서는 그렇지 않습니다. 값이 아닌 유형 만 확인하고 있습니다. 매개 변수 이름을 제거하면 더 나아지지 않으면 모든 것이 잘 작동합니다.
Mooing Duck
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.