std :: result_of와 decltype의 차이점


100

std::result_ofC ++ 0x 의 필요성을 이해하는 데 약간의 어려움이 있습니다. 내가 올바르게 이해 result_of했다면는 특정 유형의 매개 변수로 함수 객체를 호출하는 결과 유형을 얻는 데 사용됩니다. 예를 들면 :

template <typename F, typename Arg>
typename std::result_of<F(Arg)>::type
invoke(F f, Arg a)
{
    return f(a);
}

다음 코드의 차이점은 실제로 보이지 않습니다.

template <typename F, typename Arg>
auto invoke(F f, Arg a) -> decltype(f(a)) //uses the f parameter
{
    return f(a);
}

또는

template <typename F, typename Arg>
auto invoke(F f, Arg a) -> decltype(F()(a)); //"constructs" an F
{
    return f(a);
}

이 두 가지 솔루션에서 확인할 수있는 유일한 문제는 다음 중 하나가 필요하다는 것입니다.

  • decltype에 전달 된 표현식에서 사용할 functor의 인스턴스가 있습니다.
  • 펑터에 대해 정의 된 생성자를 알고 있습니다.

나는 사이의 유일한 차이는 그 권리의 생각에서 오전 decltype과는 result_of두번째하지 않는 반면 첫 번째는 식을 필요로한다는 것이다?

답변:


86

result_ofBoost도입 된TR1에 포함 되었고 마지막으로 C ++ 0x에 포함되었습니다. 따라서 result_of이전 버전과 호환되는 장점이 있습니다 (적절한 라이브러리 사용).

decltype 는 C ++ 0x에서 완전히 새로운 기능이며 함수의 반환 유형에만 제한되지 않으며 언어 기능입니다.


어쨌든 gcc 4.5에서는 다음 result_of과 같이 구현됩니다 decltype.

  template<typename _Signature>
    class result_of;

  template<typename _Functor, typename... _ArgTypes>
    struct result_of<_Functor(_ArgTypes...)>
    {
      typedef
        decltype( std::declval<_Functor>()(std::declval<_ArgTypes>()...) )
        type;
    };

4
내가 이해 decltype하는 한은 더 못 생겼지 만 더 강력합니다. result_of호출 가능한 유형에만 사용할 수 있으며 인수로 유형이 필요합니다. 예를 들어, result_of여기 에서는 사용할 수 없습니다 template <typename T, typename U> auto sum( T t, U u ) -> decltype( t + u );. 인수가 산술 유형일 수있는 경우 ( 를 나타내도록 F정의 할 수있는 함수가 없습니다 . 사용자 정의 유형의 경우 할 수 있습니다. 같은 방식으로 (실제로 해본 적이 없음) 상상합니다. 회원 메소드 호출과는 어려울 수도 바인더 또는 람다 사용하지 않고F(T,U)t+uresult_of
dribeas - 데이비드 로드리게스를

2
참고로 decltype은 AFAIK를 사용하여 함수를 호출하기 위해 인수가 필요하므로 result_of <>없이 유효한 기본 생성자를 가진 인수에 의존하지 않고 템플릿에서 반환 된 형식을 가져 오는 것이 어색합니다.
Robert Mason

3
@RobertMason : std::declval위의 코드처럼 이러한 인수는를 사용하여 검색 할 수 있습니다 . 물론 이것은 추악합니다 :)
kennytm

1
@ DavidRodríguez-dribeas 귀하의 의견에는 "(there is"로 여는 닫히지 않은 괄호가 있습니다. :(
Navin

1
또 다른 참고 사항 : result_ofand 그 도우미 유형 result_of_t은 C ++ 17에서 invoke_resultand 를 선호하여 더 이상 사용되지 않으므로 invoke_result_t전자의 일부 제한 사항이 완화됩니다. en.cppreference.com/w/cpp/types/result_of 하단에 나열되어 있습니다 .
sigma

11

함수 호출과 같은 것이 아닌 유형이 필요한 경우 std::result_of적용되지 않습니다. decltype()모든 표현의 유형을 제공 할 수 있습니다.

함수 호출의 반환 유형을 결정하는 다른 방법 ( std::result_of_t<F(Args...)>과 사이 decltype(std::declval<F>()(std::declval<Args>()...)) 으로 만 제한 하면 차이가 있습니다.

std::result_of<F(Args...) 다음과 같이 정의됩니다.

INVOKE (declval<Fn>(), declval<ArgTypes>()...)평가되지 않은 피연산자로 취급 할 때 표현식 이 잘 구성되어 있으면 (5 절) 멤버 typedef 유형이 유형을 지정 decltype(INVOKE (declval<Fn>(), declval<ArgTypes>()...)); 해야하며 그렇지 않으면 멤버 유형이 없습니다.

차이 result_of<F(Args..)>::typedecltype(std::declval<F>()(std::declval<Args>()...)그것에 대해 모든입니다 INVOKE. 사용declval/를 decltype직접 하는 것은 입력하는 데 상당히 오래 걸리는 것 외에도 F직접 호출 할 수있는 경우에만 유효합니다 (함수 객체 유형 또는 함수 또는 함수 포인터).result_of추가적으로 멤버 함수에 대한 포인터와 멤버 데이터에 대한 포인터를 지원합니다.

처음에는 SFINAE 친화적 인 표현을 사용 declval/ decltype보장하는 반면 std::result_of, 추론 실패 대신 하드 오류를 줄 수 있습니다. 이는 C ++ 14에서 수정되었습니다. std::result_of이제 SFINAE 친화적이어야합니다 ( 이 문서 덕분에 ).

따라서 준수하는 C ++ 14 컴파일러에서는 std::result_of_t<F(Args...)>엄격하게 우수합니다. 더 명확하고 짧으며 올바르게 더 많은 Fs ‡를 지원합니다 .


즉, 멤버에 대한 포인터를 허용하지 않으려는 컨텍스트에서 사용하지 않는 한 std::result_of_t실패하려는 경우 성공할 것입니다.

예외. 멤버에 대한 포인터를 지원하지만 result_of유효하지 않은 type-id 를 인스턴스화하려고하면 작동하지 않습니다 . 여기에는 함수를 반환하거나 값으로 추상 유형을 취하는 함수가 포함됩니다. 전의.:

template <class F, class R = result_of_t<F()>>
R call(F& f) { return f(); }

int answer() { return 42; }

call(answer); // nope

올바른 사용법은 였을 것입니다 result_of_t<F&()>.하지만 이것은 기억할 필요가없는 세부 사항입니다 decltype.


비 참조 유형 T및 함수의 template<class F> result_of_t<F&&(T&&)> call(F&& f, T&& arg) { return std::forward<F>(f)(std::move(arg)); }경우 사용법이 result_of_t정확합니까?
Zizheng Tai

또한 우리가 전달하는 인수 f가 a const T이면 result_of_t<F&&(const T&)>?
Zizheng Tai
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.