2017-05-19 1 views
0

static_assert를 사용하여 무언가를 강제로 실패 시키려고합니다. 특정 템플릿 함수를 특정 방식으로 인스턴스화하려고하면 컴파일러 오류가 발생합니다. 나는 그것을 작동시킬 수는 있었지만, 그것은 정말로 추악했습니다. 이 작업을 수행하는 더 쉬운 방법이 있습니까?static_assert (false)를 호출하는 올바른 방법은 무엇입니까?

이것은 첫 번째 시도였습니다. 이것은 전혀 작동하지 않았습니다. 아무도이 기능을 사용하지 않더라도 항상 오류를 생성합니다.

template< class T > 
void marshal(std::string name, T *value) 
{ 
    static_assert(false, "You cannot marshal a pointer."); 
} 

다음은 두 번째 시도입니다. 실제로 작동합니다. 이 전화를하지 않으면 오류가 발생하지 않습니다. 이 코드를 호출하면이 행을 가리키는 매우 읽기 쉬운 오류 메시지가 나타나고이를 인스턴스화하려고 시도한 코드를 가리 킵니다.

template< class T > 
void marshal(std::string name, T *value) 
{ 
    static_assert(std::is_pod<T>::value && !std::is_pod<T>::value, "You cannot marshal a pointer."); 
} 

문제는이 코드가 가장 좋지 않다는 점입니다. 해킹처럼 보입니다. 다음 번에 최적화 수준을 변경하고 내 컴파일러를 업그레이드하고 재채기 등을 할 때 컴파일러는이 두 번째 사례가 첫 번째 사례와 동일하다는 것을 인식하고 둘 다 작동하지 않을 것입니다.

내가하려는 일을하는 더 좋은 방법이 있습니까?

여기에 약간의 컨텍스트가 있습니다. 서로 다른 입력 유형에 사용할 수있는 marshal()의 여러 버전이 필요합니다. 템플릿을 기본 케이스로 사용하는 하나의 버전이 필요합니다. 나는 char *를 제외한 어떤 포인터도 특별히 허용하지 않는 또 다른 것을 원한다.

void marshal(std::string name, std::string) 
{ 
    std::cout<<name<<" is a std::string type."<<std::endl; 
} 

void marshal(std::string name, char *string) 
{ 
    marshal(name, std::string(string)); 
} 

void marshal(std::string name, char const *string) 
{ 
    marshal(name, std::string(string)); 
} 

template< class T > 
void marshal(std::string name, T value) 
{ 
    typedef typename std::enable_if<std::is_pod<T>::value>::type OnlyAllowPOD; 
    std::cout<<name<<" is a POD type."<<std::endl; 
} 

template< class T > 
void marshal(std::string name, T *value) 
{ 
    static_assert(false, "You cannot marshal a pointer."); 
} 

int main (int argc, char **argv) 
{ 
    marshal(“should be pod”, argc); 
    marshal(“should fail to compile”, argv); 
    marshal(“should fail to compile”, &argc); 
    marshal(“should be std::string”, argv[0]); 
} 
+0

에 기본 템플릿의 정의를 변경해야합니까? – cpplearner

+0

@cpplearner 일부 사람들은 선택적 매개 변수로 enable_if를 템플릿에 숨 깁니다. 호출자가 우연히 그 (가짜) 매개 변수를 채울 수 없기 때문에 이것은 더 좋아 보인다. –

답변

4

이렇게 할 방법이 없습니다. 컴파일러에서 작동하게 만들 수도 있지만 결과 프로그램은 진단이 필요하지 않습니다.

=delete을 사용하십시오.

template< class T > 
void marshal(std::string name, T *value) = delete; 
+0

흥미 롭습니다. 나는 복사 생성자 (copy constructor)와 같은 기본 메소드를 제거하는 데 사용한 delete 만 보았습니다. 네가 할 수 있다는 것도 몰랐어. 나는 그것을 시도해야 할 것이다. –

2

당신이 (심지어 해결 방법은 실패 할 수 있습니다) [temp.res]/8 (강조 광산)에 따라 잘못 형성 될 운명을하려고하고 있습니다 :

유형 이름은 이름을 아는 구문을 허용 모든 템플릿의 을 확인하십시오. 프로그램은, 필요하지 진단을 잘못 형성되지, 경우 :
- 템플릿과 템플릿 내에서 문이 인스턴스화되지 않은 경우 없이 유효 전문화 템플릿 또는 constexpr의 하위 문에 대해 생성 할 수 있습니다, 또는 모순에 의존 (...)

+0

지난 밤에 이걸 10 번 읽었다. 그리고 오늘 아침에 또. 나는 아직도 그것이 무엇을 말하는지 이해하지 못한다. : –

+1

불행히도 표준은 매우 정확하지만 때로는 이해하기 어려운 문구를 사용하여 작성되었습니다 ... 기본적으로 인스턴스를 만들 수없는 템플릿을 만들 수는 없습니다 (구조체 템플릿인지 함수 템플릿인지는 중요하지 않습니다) 어떤 매개 변수든지 ... 다른 말로하면 템플릿을 인스턴스화 할 수있는 적어도 하나의 매개 변수 집합이 있어야합니다 –

2

은 참되지 최고입니다,하지만 간단한 방법이 있습니다 :

template <class...> 
struct False : std::bool_constant<false> { }; 

template <class T> 
void bang() { 
    static_assert(False<T>{}, "bang!"); 
} 

왜이 해당되지 않습니다는 "유효한 전문화가 아닌"경우?
글쎄, 당신 때문에 실제로 코드의 두 번째 절반, 유효한 전문화를 만들 수 있습니다

물론
template <> 
struct False<int> : std::bool_constant<true> { }; 

int main() { 
    bang<int>(); // No "bang"! 
} 

은, 아무도 실제로 실제 코드에서 주장을 깰 False 전문 것 없지만 가능합니다 :)

+0

컴파일러가 유효한 전문화가 없다는 것을 알고 있다면 (즉, 소스가 있기 때문에'False'는 결코 전문화되지 않습니다. 코드), 당신의 프로그램이 아무런 진단도 필요 없다는 것을 증명하지 않겠는가? 즉,이 규칙을 피할 수있을 것인가, 아니면 그냥 알아 차리기가 더 어렵게 할 것인가? – Yakk

+0

@Yakk 나는 그것을 늘리고 있다고 생각한다. 현재 프로그램에 있지 않다는 것은 AFAICT의 범위를 벗어났다.'False'를 특수화 한 다른 바이너리를 동적으로로드하면 어떻게됩니까? 내 프로그램이 잘 형성 되었습니까? – Quentin

+0

그럼 확실하지 않습니까? 나는 정적 인 것을 허락 할 수 있기를 원하는 것에 대한 합당 성을 얻었지만, 표준은 "아니오"라고 쓰여졌다; 당신이 가장자리에 가까이있을 때 표준의 정확한 표현이 중요합니다. 전문화를 인스턴스화 할 수있는 인수가 없다고 명시되어 있습니다. 'False : std :: bool_constant {}'이 실제로'?'에 존재할 때까지는 전문화를 인스턴스화 할 수있는 인수가 없다는 것은 사실입니다. 내가 틀렸을 수도있다; 나는 종종있다. 그러나 나는 "아픈 형성, 진단 필요 없음"에 대한주의가 풍부 할 것입니다. – Yakk

1

나는 왜 당신이 template< class T > void marshal(std::string name, T *value)을 가지고 있는지 이해하지 못합니다. 이것은 기본 템플릿의 static_assert 일뿐입니다.

입니다

, 당신은 왜`형식 정의 유형 이름 표준 : enable_if`

template< class T > 
void marshal(std::string name, T value) 
{ 
    static_assert(std::is_pod<T>::value); 
    static_assert(!std::is_pointer<T>::value); 
    std::cout<<name<<" is a POD type."<<std::endl; 
} 
+0

감사합니다. 비슷한 해결책을 찾고있었습니다. 옵션이 너무 많아서 올바른 옵션을 선택하기가 어렵습니다. –

+0

다른 답변을 선택했으나 귀하의 답변은 아주 근접했습니다. = delete 옵션은 독자에게 조금 더 명백하게 보였다. 그러나 귀하의 대답은보다 융통성이 있으며 앞으로이 트릭이 필요할 수도 있습니다. 고맙습니다. –

관련 문제