2013-05-04 2 views
4

스칼라 형식 (정수, 부동 소수점 등)에 대해서만 인스턴스화 할 수있는 템플릿 클래스가 있으며 구성원의 typedef가 항상 형식의 서명 된 변형이되도록하고 싶습니다. 즉 :부동 소수점 형식을 허용하는 std :: make_signed

unsigned int ->signed int
signed long long ->signed long long (이미 서명)
unsigned char ->signed char
float ->float
long double ->long double

불행히도 std::make_signed은 부동 소수점 유형이 아닌 정수형에만 사용할 수 있습니다. 가장 간단한 방법은 무엇입니까? 내가 양식을 using SignedT = ...;, 템플릿 매개 변수 T 이미 스칼라 수 보장 내 템플릿 클래스의 일부로 찾고 있어요.

답변

8

: 나는 부동 소수점 유형에 대한 전문성 수 있도록 conditionaly하는 std::enable_if을 사용하고

#include <type_traits> 

template<typename T> 
struct identity { using type = T; }; 

template<typename T> 
using try_make_signed = 
    typename std::conditional< 
     std::is_integral<T>::value, 
     std::make_signed<T>, 
     identity<T> 
     >::type; 

을 그리고 이것은 당신이 그것을 테스트 할 수있는 방법입니다 :

int main() 
{ 
    static_assert(::is_same< 
     try_make_signed<unsigned int>::type, int 
     >::value, "!"); 

    static_assert(std::is_same< 
     try_make_signed<double>::type, double 
     >::value, "!"); 
} 

여기에 live example입니다.

+0

나는'std :: common_type '을 사용하여 자신 만의'identity' 클래스를 만드는 것을 선호한다;) –

+0

+1,'using'은 매우 편리하다. 내 컴파일러를 마지막으로 업데이트해야한다. :) – jrok

3

std::conditional을 처음 사용하다가 SFINAE를 사용하기로 결정했습니다. 간단한 템플릿 별칭 할 것

template<typename T, typename Enable = void> 
struct my_make_signed { 
    typedef typename std::make_signed<T>::type type; 
}; 

template<typename T> 
struct my_make_signed<T, 
    typename std::enable_if<std::is_floating_point<T>::value>::type> { 
    typedef T type; 
}; 
+0

'make_signed'가'T'에 특화되어 있지 않다면 에러가 나지 않습니까? (플로트의 경우). – mfontanini

+0

@mfontanini 내 나쁜, 지금은 안됩니다. 머리를 가져 주셔서 감사합니다. – jrok

+0

당신을 환영합니다 : D. 하지만 이제 조건문은 조건의 결과에 따라'std :: make_signed '(':: type'을 적용하는 경우 OK) 또는'T' (예를 들어 부동 일 수 있음) 중 하나를 생성합니다. – mfontanini

0
namespace mine {   

    template<typename T, bool b> 
    struct make_signed__ { 
     typedef T type; 
    }; 

    template<typename T> 
    struct make_signed__<T,false> { 
     typedef typename std::make_signed<T>::type type; 
    }; 

    template<typename T> 
    struct make_signed { 
     typedef typename make_signed__<T, std::is_floating_point<T>::value>::type type; 
    }; 

} 

int main() { 
    std::cout << std::is_same<mine::make_signed<unsigned int>::type, int>::value; 
    std::cout << std::is_same<mine::make_signed<long double>::type, long double>::value; 
} 
+0

그건 ' 임의로 지원되는 형식을 지원합니다 (예 : 컴파일러가'std :: uint512_t'를 지원할 수 있고 클라이언트 코드가 클래스를 인스턴스화 할 수 있습니다). –

+0

@ LB-- 네, 맞습니다. 그러나 그는 자신이 사용하는 것을 정의하기 만하면됩니다. 그런데'std :: make_signed'가 이들을 지원합니까? – stardust

+0

예, 컴파일러 구현에 의해 정의 되었기 때문에 필수입니다. –

2

@jrok는 원래 작동 할 수있는 코드를 가지고 있었지만 작은 조정 만하면되었습니다. 이 작업 코드 :

template<typename T> 
struct YourClass 
{ 
    using SignedT = 
     typename std::conditional 
     < 
      std::is_floating_point<T>::value, //if floating point type 
      std::common_type<T>,    //use it as-is 
      std::make_signed<T>    //otherwise make sure it is signed 
     >::type::type; //notice the double ::type 
}; 

데모 :이 기능은 여러 번 사용해야하는 경우 유형 특성 클래스가 위의 구조체는 그 자체로 수정할 수 http://ideone.com/Vw7o82

. 그러나 @Andy Prowl의 대답은 별칭 템플릿으로 처리하는 것이 더 좋습니다.

+0

이 방법이 유용하지만 매번 정의해야한다는 단점이 있습니다. 내 답변에있는 별칭 템플릿을 사용하면'SignedT = typename try_make_signed :: type'을 사용하면됩니다. 그러면 끝났습니다. –

+0

이 답변의 클래스는 유형 특성 클래스로 쉽게 리팩터링 될 수 있으므로 '단점'이 무엇인지 알지 못합니다. 우리의 답변이 동일하면 맞습니까? –

+0

충분하다. 형체 형을 만들기 위해 그것을 수정할 수있다. 그렇다. 내 대답에있는 별칭 템플릿을 사용하면 더 좋다. –

관련 문제