static_warning이 있습니까?
저는 Boost의 "STATIC WARNING"을 언급하는 이 질문 에 대해 알고 있지만, 구체적으로 static_warning유사하게 작동 static_assert하지만 컴파일 오류가 아닌 컴파일 타임 에만 경고 를 내는 a 를 구현할 수있는 방법을 다시 묻고 싶습니다 .
나는 오류의 일부로 유용한 컨텍스트 정보를 어떻게 든 인쇄 할 수 있었던 pre-C ++ 11 일의 정적 주장에 대한 Alexandrescu의 제안과 유사한 것을 원합니다.
이 구성이 작동하려면 사용자가 특정 표준 컴파일러 경고를 활성화하도록 요구하는 것이 허용됩니다 ( "잘못된 포인터 변환"또는 "엄격한 앨리어싱 규칙 위반"). 어쨌든 일반 컴파일의 일부 여야하는 모든 경고는 사용됩니다.
간단히 말해, static_warning(false, "Hello world");경고 메시지에 "hello world"문자열을 포함해야하는 컴파일러 경고를 만들고 싶습니다 . GCC 및 MSVC에서 이것이 가능합니까?
특별히 영리한 솔루션에 대해 기꺼이 작은 보상을드립니다.
약간의 설명으로 : 이 질문 에 대해 생각할 때 아이디어를 얻었습니다 . 정적 경고는 복잡한 템플릿 전문화의 컴파일 타임 프로세스를 추적하는 유용한 방법이 될 것입니다. 그렇지 않으면 디버그하기가 상당히 어렵습니다. 정적 경고는 컴파일러가 "이제 코드의이 부분을 컴파일하고 있습니다."를 내보내는 간단한 신호로 사용할 수 있습니다.
최신 정보. 이상적으로 경고는 다음 설정에서 트리거됩니다.
template <typename T> struct Foo
{
static_warning(std::is_pointer<T>::value, "Attempting to use pointer type.");
// ...
};
int main() { Foo<int> a; Foo<int*> b; }
Michael E의 의견에서 재생 :
#if defined(__GNUC__)
#define DEPRECATE(foo, msg) foo __attribute__((deprecated(msg)))
#elif defined(_MSC_VER)
#define DEPRECATE(foo, msg) __declspec(deprecated(msg)) foo
#else
#error This compiler is not supported
#endif
#define PP_CAT(x,y) PP_CAT1(x,y)
#define PP_CAT1(x,y) x##y
namespace detail
{
struct true_type {};
struct false_type {};
template <int test> struct converter : public true_type {};
template <> struct converter<0> : public false_type {};
}
#define STATIC_WARNING(cond, msg) \
struct PP_CAT(static_warning,__LINE__) { \
DEPRECATE(void _(::detail::false_type const& ),msg) {}; \
void _(::detail::true_type const& ) {}; \
PP_CAT(static_warning,__LINE__)() {_(::detail::converter<(cond)>());} \
}
// Note: using STATIC_WARNING_TEMPLATE changes the meaning of a program in a small way.
// It introduces a member/variable declaration. This means at least one byte of space
// in each structure/class instantiation. STATIC_WARNING should be preferred in any
// non-template situation.
// 'token' must be a program-wide unique identifier.
#define STATIC_WARNING_TEMPLATE(token, cond, msg) \
STATIC_WARNING(cond, msg) PP_CAT(PP_CAT(_localvar_, token),__LINE__)
매크로는 네임 스페이스, 구조 및 함수 범위에서 호출 될 수 있습니다. 입력이 주어지면 :
#line 1
STATIC_WARNING(1==2, "Failed with 1 and 2");
STATIC_WARNING(1<2, "Succeeded with 1 and 2");
struct Foo
{
STATIC_WARNING(2==3, "2 and 3: oops");
STATIC_WARNING(2<3, "2 and 3 worked");
};
void func()
{
STATIC_WARNING(3==4, "Not so good on 3 and 4");
STATIC_WARNING(3<4, "3 and 4, check");
}
template <typename T> struct wrap
{
typedef T type;
STATIC_WARNING(4==5, "Bad with 4 and 5");
STATIC_WARNING(4<5, "Good on 4 and 5");
STATIC_WARNING_TEMPLATE(WRAP_WARNING1, 4==5, "A template warning");
};
template struct wrap<int>;
GCC 4.6 (기본 경고 수준)은 다음을 생성합니다.
static_warning.cpp : 생성자 'static_warning1 :: static_warning1 ()'에서 :
static_warning.cpp : 1 : 1 : 경고 : 'void static_warning1 :: _ (const detail :: false_type &)'
더 이상 사용되지 않습니다 (static_warning.cpp : 1에 선언 됨) : 1 및 2로 실패 함 [-Wdeprecated-declarations]
static_warning.cpp : 생성자 'Foo :: static_warning6 :: static_warning6 ()'에서 :
static_warning.cpp : 6 : 3 : 경고 : 'void Foo :: static_warning6 :: _ (const detail :: false_type &)'
더 이상 사용되지 않습니다 (static_warning.cpp : 6에 선언 됨) : 2 및 3 : 죄송합니다 [-Wdeprecated-declarations]
static_warning.cpp : 생성자 'func () :: static_warning12 :: static_warning12 ()'에서 :
static_warning.cpp : 12 : 3 : 경고 : 'void func () :: static_warning12 :: _ (const detail :: false_type &)'
더 이상 사용되지 않습니다 (static_warning.cpp : 12에 선언 됨) : 3과 4에서는 좋지 않음 [-Wdeprecated-declarations]
static_warning.cpp : 생성자 'wrap <T> :: static_warning19 :: static_warning19 () [with T = int]':
static_warning.cpp : 24 : 17 : 여기에서 인스턴스화 됨
static_warning.cpp : 19 : 3 : 경고 : 'void wrap <T> :: static_warning19 :: _ (const detail :: false_type &) [with T = int]'
더 이상 사용되지 않습니다 (static_warning.cpp : 19에 선언 됨) : 4 및 5에 적합하지 않음 [-Wdeprecated-declarations]
Visual C ++ 2010 (/ W3 이상)에서는 다음과 같이 말합니다.
warnproj.cpp (1) : 경고 C4996 : 'static_warning1 :: _': 1과 2로 실패
warnproj.cpp (1) : 'static_warning1 :: _'선언 참조
warnproj.cpp (6) : 경고 C4996 : 'Foo :: static_warning6 :: _': 2 및 3 : 죄송합니다.
warnproj.cpp (6) : 'Foo :: static_warning6 :: _'선언 참조
warnproj.cpp (12) : 경고 C4996 : 'func :: static_warning12 :: _': 3과 4에서 좋지 않음
warnproj.cpp (12) : 'func :: static_warning12 :: _'선언 참조
warnproj.cpp (19) : 경고 C4996 : 'wrap <T> :: static_warning19 :: _': 4 및 5에서 잘못됨
와
[
T = int
]
warnproj.cpp (19) : 'wrap <T> :: static_warning19 :: _'선언 참조
와
[
T = int
]
warnproj.cpp (19) : 클래스 템플릿 멤버 함수 'wrap <T> :: static_warning19 :: static_warning19 (void)'를 컴파일하는 동안
와
[
T = int
]
warnproj.cpp (24) : 컴파일중인 클래스 템플릿 인스턴스화 'wrap <T> :: static_warning19'에 대한 참조 참조
와
[
T = int
]
Linux의 Clang ++ 3.1은 틀림없이 더 좋은 출력을 생성합니다 (색상 표시되지 않음).
tst3.cpp : 1 : 1 : 경고 : '_'는 더 이상 사용되지 않습니다. 1과 2로 실패했습니다.
[-Wdeprecated-declarations]
STATIC_WARNING (1 == 2, "1과 2로 실패");
^
tst3.cpp : 24 : 38 : 참고 : 'STATIC_WARNING'매크로에서 확장 됨
PP_CAT (static_warning, __ LINE __) () {_ (:: detail :: converter <(cond)> ());} \
^
tst3.cpp : 6 : 3 : 경고 : '_'는 더 이상 사용되지 않습니다. 2 및 3 : 죄송합니다.
[-Wdeprecated-declarations]
STATIC_WARNING (2 == 3, "2 및 3 : 죄송합니다");
^
tst3.cpp : 24 : 38 : 참고 : 'STATIC_WARNING'매크로에서 확장 됨
PP_CAT (static_warning, __ LINE __) () {_ (:: detail :: converter <(cond)> ());} \
^
tst3.cpp : 12 : 3 : 경고 : '_'는 더 이상 사용되지 않습니다. 3과 4에서는 좋지 않습니다.
[-Wdeprecated-declarations]
STATIC_WARNING (3 == 4, "3과 4에서는 좋지 않음");
^
tst3.cpp : 24 : 38 : 참고 : 'STATIC_WARNING'매크로에서 확장 됨
PP_CAT (static_warning, __ LINE __) () {_ (:: detail :: converter <(cond)> ());} \
^
tst3.cpp : 19 : 3 : 경고 : '_'는 더 이상 사용되지 않음 : 4 및 5에서 불량
[-Wdeprecated-declarations]
STATIC_WARNING (4 == 5, "4와 5에서 나쁨");
^
tst3.cpp : 24 : 38 : 참고 : 'STATIC_WARNING'매크로에서 확장 됨
PP_CAT (static_warning, __ LINE __) () {_ (:: detail :: converter <(cond)> ());} \
^
tst3.cpp : 23 : 17 : 참고 : 멤버 함수 인스턴스화
'wrap <int> :: static_warning19 :: static_warning19'요청
템플릿 구조체 wrap <int>
^
4 개의 경고가 생성되었습니다.
여기 내가 지금까지 생각 해낸 최고가 있습니다. 기본적이고 요구 사항에 맞지 않지만 대신 BOOST_MPL_ASSERT_MSG메시지가 유효한 식별자 형식을 취해야하는 경로로 이동합니다 . (내가 아는 한, 경고 메시지에 인쇄 된 문자열을 얻을 수있는 유일한 방법은 사용한 경고가 문자열과 관련된 경고이고 그 내용을 인쇄하는 경우입니다.)
사용하지 않는 변수에 대한 경고를 활성화해야합니다. g ++에서는 -Wunused-variable(으로 활성화 됨 -Wall)이고 MSVC에서는 경고 수준 3에서 활성화 된 경고 C4101입니다.
It's obviously not very tested and could be enhanced in a few ways (use __COUNTER__ instead of __LINE__ on supported compilers, prettier message printing, use Boost to simplify, etc.), but seems to get the job done. Here's the boiler-plate:
namespace detail
{
template <bool Condition>
struct static_warning;
template <>
struct static_warning<true>
{
template <typename Message>
static void warn() {}
};
template <>
struct static_warning<false>
{
// If you're here because of a warning, please see where the
// template was instantiated for the source of the warning.
template <typename Message>
static void warn() { Message STATIC_WARNING_FAILED; }
};
}
#define STATIC_WARNING_DETAIL_EX(cond, msg, line) \
struct static_warning ## line \
{ \
class msg {}; \
\
static_warning ## line() \
{ \
::detail::static_warning<(cond)>:: \
warn<void************ (msg::************)()>(); \
} \
}
#define STATIC_WARNING_DETAIL(cond, msg, line) \
STATIC_WARNING_DETAIL_EX(cond, msg, line)
// Use these:
#define STATIC_WARNING_MSG(cond, msg) \
STATIC_WARNING_DETAIL(cond, msg, __LINE__)
#define STATIC_WARNING(cond) \
STATIC_WARNING_DETAIL(cond, STATIC_WARNING_FAILED, __LINE__)
And a test:
STATIC_WARNING(sizeof(int) == 2);
int main()
{
STATIC_WARNING_MSG(sizeof(char) != 1, JUST_KIDDING_ALL_IS_WELL);
}
In MSVC this produces:
>main.cpp(19): warning C4101: 'STATIC_WARNING_FAILED' : unreferenced local variable
> main.cpp(45) : see reference to function template instantiation 'void detail::static_warning<false>::warn<void************(__thiscall static_warning45::STATIC_WARNING_FAILED::* ***********)(void)>(void)' being compiled
>main.cpp(19): warning C4101: 'STATIC_WARNING_FAILED' : unreferenced local variable
> main.cpp(49) : see reference to function template instantiation 'void detail::static_warning<false>::warn<void************(__thiscall main::static_warning49::JUST_KIDDING_ALL_IS_WELL::* ***********)(void)>(void)' being compiled
And in GCC it produces:
main.cpp: In static member function 'static void detail::static_warning<false>::warn() [with Message = void************ (static_warning39::STATIC_WARNING_FAILED::************)()]':
main.cpp:39:1: instantiated from here
main.cpp:19:38: warning: unused variable 'STATIC_WARNING_FAILED'
main.cpp: In static member function 'static void detail::static_warning<false>::warn() [with Message = void************ (main()::static_warning43::JUST_KIDDING_ALL_IS_WELL::************)()]':
main.cpp:43:5: instantiated from here
main.cpp:19:38: warning: unused variable 'STATIC_WARNING_FAILED'
Here is a solution that uses the Boost MPL library:
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/print.hpp>
#define static_warning_impl2(cond, msg, line) \
struct static_warning_ ## line { \
struct msg {}; \
typedef typename boost::mpl::eval_if_c< \
cond, \
boost::mpl::identity<msg>, \
boost::mpl::print<msg> \
>::type msg ## _; \
}
#define static_warning_impl1(cond, msg, line) \
static_warning_impl2(cond, msg, line)
#define static_warning(cond, msg) \
static_warning_impl1(cond, msg, __LINE__)
It comes with the same restriction as GMan's solution: the message must be a valid identifier. Here are two tests
static_warning(sizeof(int) == 4, size_of_int_is_not_4);
and
static_warning(sizeof(int) == 2, size_of_int_is_not_2);
With MSVS 2010 the first test compiles without warnings, the second compiles with the warning
C:\Libraries\Boost\boost_1_48_0\boost/mpl/print.hpp(51): warning C4308: negative integral constant converted to unsigned type
C:\Libraries\Boost\boost_1_48_0\boost/mpl/eval_if.hpp(63) : see reference to class template instantiation 'boost::mpl::print<T>' being compiled
with
[
T=static_warning_28::size_of_int_is_not_2
]
Test.cpp(28) : see reference to class template instantiation 'boost::mpl::eval_if_c<C,F1,F2>' being compiled
with
[
C=false,
F1=boost::mpl::identity<static_warning_28::size_of_int_is_not_2>,
F2=boost::mpl::print<static_warning_28::size_of_int_is_not_2>
]
The code uses boost::mpl::print. From the book C++ Template Metaprogramming by D. Abrahams and A. Gurtovoy, page 171:
To generate a compile-time execution log, we'd need a way to generate a diagnostic message - a warning. Because there's no single construct that will cause all compilers to generate a warning (indeed, most compilers let you disable warnings altogether), MPL has a print metafunction that is just like identity except that it is tuned to generate a warning on a variety of popular compilers with their usual settings.
참고URL : https://stackoverflow.com/questions/8936063/does-there-exist-a-static-warning
'Program Club' 카테고리의 다른 글
| 브라우저에서 보낸 HTTP 요청의 헤더를 변경할 수 있습니까? (0) | 2020.11.18 |
|---|---|
| JQuery Ajax 호출 기본 시간 초과 값 (0) | 2020.11.18 |
| Microsoft.WindowsAzure.ServiceRuntime 용 NuGet 패키지는 어디에 있습니까? (0) | 2020.11.18 |
| 우산 헤더는 무엇입니까? (0) | 2020.11.18 |
| 데이터 가져 오기시 Firestore 성능 저하 문제 (0) | 2020.11.18 |