2017-03-19 10 views
2

저는 CLion 2016.3.4에서 개발중인 C++ 14 프로젝트를 가지고 있으며, 코드의 한 조각으로 인해 검사 오류가 발생했습니다.SFINAE 제거, Constexpr 및 함수 템플릿 : 선언과 정의를 별도로 유지할 수 있습니까?

#include <iostream> 
#include <type_traits> 
#include <system_error> 

using error_id_type = int; 

template <typename T> using enable_if_condition_enum_t = 
    typename std::enable_if<std::is_error_condition_enum<T>::value, T>::type; 

// Declaration 
template <typename T, typename = enable_if_condition_enum_t<T>> 
    constexpr error_id_type error_enum_to_int(T elem) noexcept; 

// Definition 
template <typename T, typename = enable_if_condition_enum_t<T>> 
constexpr error_id_type error_enum_to_int(T elem) noexcept { 
    return static_cast<error_id_type>(elem); 
}; 

int main(void) { 
    error_id_type condition = error_enum_to_int(std::errc::owner_dead); // inspection error here 
    switch (condition) { 
    case error_enum_to_int(std::errc::address_in_use): break; // inspection error here 
    default: break; 
    } 
    std::cout << condition << std::endl; 
    return 0; 
} 

CLion이 error_enum_to_int의 모든 호출 발생 나에게 Call to "error_enum_to_int" is ambiguous을 제공합니다 : 나는 문제를 재현하기위한 최소한의 코드를 만들었습니다. 그런 종류의 사용에 실제로 어떤 문제가 있습니까? ,

  • 이 선언을 삭제하고 (작품 만의 정의를두고,하지만 난 같은 컴파일 단위에서 다른 위치에서 그들을 유지하고 싶었 :

    어떤 것들은 내가 시도했지만 그건 정말 이럴 해결되지 않습니다 가능한 경우);

  • SFINAE 템플릿 인수를 삭제합니다 (작동하지만 모든 유형에 사용할 수 있습니다. 의도는 아닙니다).
  • enable_if_condition_enum_t<T>으로 대체하면 T 인수가됩니다 (작동하지 않아서 컴파일 및 검사 오류가 완전히 수정되었습니다).

코드는 g++ (GCC) 6.3.1 20170306에 수정없이 잘 컴파일되어 실행됩니다. 불행히도, 나는 지금 이것을 시험해보기 위해 다른 컴파일러에 접근 할 수 없지만, 이것이 표준의 휴대용 C++ 11이라고 생각한다.

물론 언제나 static_cast<some_enum_class>(some_int)에 대한 옵션이 있지만,이 코드 스 니펫에 어떤 문제가 있는지 구체적으로 알고 싶습니다.

내 질문은 : 이것은 내 IDE의 버그이며, 실제로 인식하지 못하는 언어의 경우이거나 정말 멍청한 뭔가를하고있는 것입니까 (: D)?

내 추론

내가 잘못하면 저를 시정하십시오.

자체 선언은 함수 템플릿 인 경우에도 정의가 아닙니다. 함수 템플릿 자체는 인스턴스화 될 때까지 실제로 함수가 아닙니다. 그럼에도 불구하고 컴파일러는 두 함수가 동일한 컴파일/변환 단위에있는 한 동일한 함수 템플릿의 두 가지 발생이 있고 다른 하나를 혼동하지 않는 것을 볼 수 있어야합니다. CLion (또는 clang의 정적 분석기)은 선언을 정의로 간주하고 다른 것으로 해석합니다. 그리고 두 가지 모두 템플릿이기 때문에 어떤 것을 인스턴스화할지 혼란 스럽습니다.

선언과 정의가 모두 같은 컴파일 단위에 있음에 유의하십시오. 또한 constexprinline을 의미하므로 하나의 정의 규칙이 계속 적용됩니다. 또한, 인수로 사용되는 열거 형을 std::error_condition 열거 형으로 선언하지 않은 경우 SFINAE 기반 제거에 enable_if_condition_enum_t을 사용합니다.

UPDATE

@Angew's answer에 따라, 여기에 올바른 선언과 error_enum_to_int의 정의입니다.

// Declaration 
template <typename T, typename = enable_if_condition_enum_t<T>> 
    constexpr error_id_type error_enum_to_int(T elem) noexcept; 

// Definition 
template <typename T, typename> 
constexpr error_id_type error_enum_to_int(T elem) noexcept { 
    return static_cast<error_id_type>(elem); 
}; 
+0

@ 앤그 정확한! aswer를 만들어서 받아 들일 수 있을까요? –

답변

2

C++에서는 동일한 매개 변수/템플릿 매개 변수에 기본 인수 또는 기본 템플릿 인수를 두 번 이상 제공 할 수 없습니다.함수의 모든 선언 (정의 포함)의 기본 [템플릿] 인수는 결합 (계단식)됩니다. 템플리트의 정의에서 기본 템플리트 인수를 제거해야합니다.