>source

기본 값 ( ::type = 0 )을 사용해야하는 이유 이 std::enable_if 에서  사용법?

예제없이 작동하는 예제를 봅니다. 예를 들어 https://foonathan.net/blog/2015/ 11/30/overload-resolution-4.html

#include<iostream>
#include<type_traits>
template <typename T,
          typename std::enable_if<std::is_integral<T>::value, T>::type = 0>
void do_stuff(T t) {
    std::cout << "do_stuff integral\n";
}
template <typename T,
          typename std::enable_if<std::is_class<T>::value, T>::type = 0>
void do_stuff(T t) {
    std::cout << "do_stuff class\n";
}
int main()
{
    do_stuff(32);
    return 0;
}

오류 메시지가 나타납니다 :

temp.cpp:6:6: note:   template argument deduction/substitution failed:
temp.cpp:18:13: note:   couldn't deduce template parameter ‘<anonymous>’

추론되어야한다

template <template T, int>
void do_stuff(T t)

유효한 코드입니다. 내가 뭘 잘못하고 있니? (gcc버전7.4.0)


  • 답변 # 1

    컴파일러는 문제가 무엇인지 명확하게 알려줍니다. 템플릿 선언에서 추론 할 수없는 추가 템플릿 비 유형 매개 변수를 지정했습니다. 컴파일러가 해당 유형이 아닌 매개 변수에 적절한 값을 추론하는 방법은 무엇입니까? 무엇에서?

    이것이 바로 std::enable_if 를 사용하는 위의 기술입니다.  기본 인수가 필요합니다. 이는 더미 매개 변수이므로 기본 인수 값은 중요하지 않습니다 ( 0  당연한 선택입니다).

    예제를 단순한 것으로 줄일 수 있습니다

    template <typename T, T x> 
    void foo(T t) {}
    int main()
    {
      foo(42);
    }
    
    

    제작

    error: no matching function for call to 'foo(int)'
    note:   template argument deduction/substitution failed:
    note:   couldn't deduce template parameter 'x'
    
    

    컴파일러는 T 를 추론 할 수있다  입니다 ( T == int ), 그러나 컴파일러가 x 에 대한 인수를 추론 할 방법이 없습니다. .

    두 번째 템플릿 매개 변수의 이름이 지정되지 않은 것 (더미 매개 변수의 이름을 지정할 필요가 없음)을 제외하고 코드는 동일합니다.

    <시간>

    귀하의 의견으로 판단하면 키워드 typename 의 존재로 혼란스러워하는 것 같습니다  코드에서 두 번째 매개 변수 선언에서 두 번째 매개 변수가유형매개 변수라고 생각하게합니다. 후자는 사실이 아닙니다.

    두 번째 매개 변수의 선언 키워드 typename 에서  완전히 다른 역할에서 사용됩니다. 이 키워드는 단순히

    의 의미를 명확하게합니다.
    std::enable_if<std::is_class<T>::value, T>::type
    
    

    컴파일러에게 type 라는 중첩 이름을 알려줍니다.  실제로는 다른 이름이 아닌유형의 이름을 나타냅니다. ( typename 사용법에 대해 읽을 수 있습니다.  here : 왜 여기에 typename이 필요합니까? "템플릿"및 "typename"키워드를 어디에 그리고 왜 넣어야합니까?)

    typename 사용법  템플릿의 두 번째 매개 변수를유형매개 변수로 바꾸지 마십시오. 템플릿의 두 번째 매개 변수는 여전히비 유형매개 변수입니다.

    다음은 코드에서 일어나는 일을 보여주는 간단한 예입니다.

    struct S { typedef int nested_type; };
    template <typename T, typename T::nested_type x>
    void bar(T t)
    {}
    int main()
    {
      S s;
      bar<S, 42>(s);
    }
    
    

    두 번째 매개 변수의 선언이 typename 로 시작하더라도 , 여전히 유형이 아닌 매개 변수를 선언합니다.

  • 답변 # 2

    오류를 재현 할 수 없습니다. 어쨌든 do_stuff() 호출 오류가 발생합니다  수업과 함께. 예를 들어

    do_stuff(std::string{"abc"})
    
    

    이것은 do_stuff() 때문입니다   do_stuff<std::string, std::string = 0>() 가되다  템플릿 값은 std::string 유형일 수 없습니다.  (기본값은 0이 아님)

    제안 : int 를 부과하는 함수를 다시 작성하십시오.  두 번째 위치의 값 유형으로

    template <typename T, // .....................................VVV  int, not T
              typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
    void do_stuff(T t) {
        std::cout << "do_stuff integral\n";
    }
    template <typename T, // ..................................VVV  int, not T
              typename std::enable_if<std::is_class<T>::value, int>::type = 0>
    void do_stuff(T t) {
        std::cout << "do_stuff class\n";
    }
    
    
    이 방법으로 do_stuff(std::string{"abc"}) 를 호출 , do_stuff<std::string, int = 0>() 를 활성화합니다  괜찮습니다.

관련 자료

  • 이전 perl6 - 문법 동작이 6c와 6d 사이에서 깨졌습니까?
  • 다음 Python Panda의 참조 유형 목록과 관련된 정렬 문제