C ++ 11에서 사용되지 않는 매개 변수


79

C ++ 03 및 이전 버전에서는 사용되지 않는 매개 변수에 대한 컴파일러 경고를 비활성화하기 위해 일반적으로 다음 코드를 사용합니다.

#define UNUSED(expr) do { (void)(expr); } while (0)

예를 들면

int main(int argc, char *argv[])
{
    UNUSED(argc);
    UNUSED(argv);

    return 0;
}

그러나 매크로는 C ++의 모범 사례가 아닙니다. C ++ 11 표준에 더 나은 솔루션이 있습니까? 매크로를 제거 할 수 있습니까?

모두 감사합니다!


11
확실한. 경고를 끄십시오.
— Pete Becker

65
아니! 그거 하지마!
— 궤도의 경쾌함 경주

9
매크로를 인라인으로 확장하는 것보다 얼마나 더 나은가요? (void)argc;보다 짧고 명확UNUSED(argc);
— 데이비드 로드리게스 - dribeas는

22
내가 좋아하는 unused(argc, argv)과 template<class... T> void unused(T&&...){}. 명확하고 간결하며 매크로가 없습니다.
— Xeo 2013-04-02

19
@MadScientist이지만 이름없는 인수를 남겨 두거나 이름을 주석으로 처리 할 수도 있습니다. void foo(int /*unused_arg*/, int used_arg)
— kassak 2013

답변:


41

나는 그 목적으로 빈 본문을 가진 함수를 사용했습니다.

template <typename T>
void ignore(T &&)
{ }

void f(int a, int b)
{
  ignore(a);
  ignore(b);
  return;
}

심각한 컴파일러가 함수 호출을 최적화하기를 기대하고 경고를 표시하지 않습니다.


20
When Tis a template parameter, T&&is a universal reference that binds to any. 템플릿 매개 변수 는 무엇이든 바인딩 하는 범용 참조 입니다.
— 문헌 : Angew는 더 이상 자랑 SO의없는

4
+1 비록 그의 코멘트에서 Xeo 의 고급 버전이 언급되지 않았지만.
— Christian Rau 2013

12
기본 제공 방법을 무시하는 이유는 무엇입니까? 매개 변수 이름을 생략하기 만하면됩니다.
— Jack Aidley 2013

27
-1, 이것은 특히 매개 변수 이름을 생략 할 수있는 경우 우스꽝스럽고 불필요한 장치입니다. 솔직히, 이것이 어떻게 든 25 개의 업보를 가지고 있다는 것이 나를 괴롭 힙니다.
— TC1 2013-04-03

5
@ TC1 이것은 코드가하는 일과 이유에 대해 코드를 명시 적으로 만듭니다. 사용하지 않는 매개 변수 나 변수를 사용하는 것은 코드에서 냄새가납니다. 경고를 끄면 코드 냄새가 더 커집니다.
— dascandy

205

매개 변수 이름을 생략 할 수 있습니다.

int main(int, char *[])
{

    return 0;
}

그리고 main의 경우 매개 변수를 모두 생략 할 수도 있습니다.

int main()
{
    // no return implies return 0;
}

C ++ 11 표준의 "§ 3.6 시작 및 종료"를 참조하십시오.


12
의 경우 main매개 변수를 모두 생략 할 수 있습니다. 그리고 return그 문제에 대한 진술.
— Mike Seymour

4
@MikeSeymour 실제로 return 문을 생략하는 것이 좋은 습관이라고 생각합니다.
— jtepe 2013-04-02

6
@jotep 좋아, 내가 물어볼 게. 왜 그것을 좋은 습관이라고 생각합니까?
— Peter Wood

6
거의 항상 테스트 케이스에서 main's return 0를 생략 하지만 거의 항상 return EXIT_SUCCESS프로덕션 코드에서 자체 문서화 를 작성합니다. 그것은 좋은 연습입니다!
— 궤도의 밝기 경주

30
이것은 나에게 가장 좋은 대답 인 것 같습니다. 매크로 나 템플릿을 사용하는 모든 것이 나중에 변수를 사용할 수 없다는 것을 보장하지 않습니다. 이 두 침묵 경고 및 제 (익명) 매개 변수 적 사용할 수 없음을 보장합니다.
— Alnitak

51

거기 <tuple>에 C ++ (11) 사용에 대한 준비를 포함, std::ignore의는 (런타임 오버 헤드를 부과하지 않고 가능성이 매우 높다) 쓰기 우리를 허용하는지, 객체 :

void f(int x)
{
    std::ignore = x;
}

4
이것이 표준 라이브러리에 있으므로 사용자 지정 함수를 작성할 필요가 없다는 점을 고려하면 이것이 최상의 솔루션이라고 말하고 싶습니다!
— BrainStone 2016

2
이 클래스는 "std :: tuple의 압축을 풀 때 std :: tie와 함께 사용하기위한 것입니다."이 사용 사례가 아닙니다. 나는 그것이 해결책이라고 말하고 싶지만 아마도 최선은 아닙니다.
— Maestro

1
실제로 무시하는 것이 좋습니다. Ofc, 매개 변수를 제거 할 수 있으면 대신 제거하십시오 (모든 경우에 최상의 솔루션이 될 것입니다).
— danger89

33

이 경고를 "비활성화"하려면 인수 작성을 피하고 유형 만 작성하는 것이 가장 좋습니다.

void function( int, int )
{
}

또는 원하는 경우 주석 처리 :

void function( int /*a*/, int /*b*/ )
{
}

명명 된 인수와 명명되지 않은 인수를 혼합 할 수 있습니다.

void function( int a, int /*b*/ )
{
}

로 17 ++ C 당신이 [[maybe_unused] 속성 지정, 같은 :

void function( [[maybe_unused]] int a, [[maybe_unused]] int b )
{
}

2
나는이 작업을 수행하는 데 사용하지만, 더 이상 사용하여 코드의 큰 덩어리를 주석 수 있기 때문에 신속 고통이된다/* ... */
— Ponkadoodle을

1
사실이지만 최신 IDE에서는 자동으로 주석 처리 할 블록을 선택하면 각 줄의 시작 부분에 "//"가 추가됩니다. 이것이 Eclipse CDT가하는 일입니다. 개인적으로 저는 이름이없는 첫 번째 예만 사용합니다. (예를 들어 .h 파일의 선언에 이름을 넣을 수 있습니다).
— Nikko

5
@Wallacoloo 큰 덩어리의 코드를 주석 처리하고 싶을 때 #if 0 ... #endif를 사용합니다.이 코드는 중첩이 허용되고 기존 / * ... * / 주석과 충돌하지 않습니다.
— Dmitry Frank

1
@DmitryFrank 그리고 대부분의 편집기와 IDE #if 0는 전체 전 처리기 인텔리 센스를 지원하지 않더라도 특수한 경우로 블록을 회색 으로 표시하는 것을 지원합니다.
— Thomas

30

동등한 것은 없습니다.

그래서 당신은 똑같은 오래된 옵션을 고수하고 있습니다. 매개 변수 목록에서 이름을 완전히 생략 할 수 있습니까?

int main(int, char**)

main물론 의 특정 경우에는 단순히 매개 변수 자체를 생략 할 수 있습니다.

int main()

GCC와 같은 일반적인 구현 관련 트릭도 __attribute__((unused))있습니다.


14

매크로는 이상적이지 않을 수 있지만 이러한 특정 목적에 적합합니다. 나는 매크로 사용을 고수하고 싶다.


6
+1 :이 경우 해를 끼치 지 않고 문제를 해결합니다. 나는 여기에 그것들을 사용하지 않을 이유 ( "매크로를 사용하지 않는다"라는 말도 안되는 근거없는 만트라를 넘어서)를 보지 못한다.
— 궤도의 가벼운 경주

1
매개 변수 이름을 완전히 생략하는 것보다 매크로의 이점은 무엇입니까?
— Micha Wiedenmann 2013

1
@MichaWiedenmann : 일부 매개 변수는 일부 전처리 상수가 설정된 경우에만 사용할 수 있습니다 (일반적으로 디버그에서).
— Matthieu M.

2
@MatthieuM .: 나는 MAYBE_UNUSED그 이유 때문에 매크로라고 부를 것 입니다; 일반적으로 "아래에서 이걸 사용하지 않아도 걱정하지 마세요"라고 말했더라도 상관하지 않지만 계속 사용합니다.
— 궤도의 경쾌함 경주

2
좋습니다. 올바른 것은 아마도 "HIDE_UNUSED_WARNING"이라고 부르는 것입니다. 하지만 여기에서 매크로를 사용하는 것이 완벽하게 유효한 아이디어라고 생각합니다. 다른 코드와 혼동 및 / 또는 충돌을 일으키지 않는 방식으로 매크로의 이름이 지정되는 한.
— Mats Petersson 2013-04-02

13

구식 및 표준 방식에 대해 무엇을 가지고 있습니까?

void f(int a, int b)
{
  (void)a;
  (void)b;
  return;
}

일부 컴파일러는 이것에 만족하지만 일부 컴파일러는 다른 컴파일러보다 까다 롭습니다. 크로스 플랫폼 작업은 모든 대상 OS 및 컴파일러에서 테스트하여 솔루션에 모두 만족하는지 확인해야합니다.
— Jesse Chisholm은

12

새로운 것이 없습니다.

나에게 가장 적합한 것은 구현에서 매개 변수 이름을 주석 처리하는 것입니다. 이렇게하면 경고는 제거되지만 매개 변수가 무엇인지에 대한 일부 개념은 유지됩니다 (이름을 사용할 수 있으므로).

매크로 (및 기타 모든 Cast-to-void 접근 방식)에는 매크로를 사용한 후 실제로 매개 변수를 사용할 수 있다는 단점이 있습니다. 이로 인해 코드 유지 관리가 더 어려워 질 수 있습니다.


12

Boost 헤더 <boost/core/ignore_unused.hpp>(Boost> = 1.56)는이를 위해 함수 템플릿을 정의합니다 boost::ignore_unused().

int fun(int foo, int bar)
{
  boost::ignore_unused(bar);
#ifdef ENABLE_DEBUG_OUTPUT
  if (foo < bar)
    std::cerr << "warning! foo < bar";
#endif

  return foo + 2;
}

PS C ++ 17에는 [[maybe_unused]]사용하지 않는 엔티티에 대한 경고를 억제 하는 속성이 있습니다.


1
[[maybe_unused]]현재 가장 좋은 방법입니다.
— Tomilov Anatoliy 2016

0

다른 디버그 빌드가있을 때 (예 : 어설 션을 활성화하여 빌드하려는 경우) 더 잘 제어 할 수 있기 때문에 매크로를 사용하는 것을 정말 좋아합니다.

#if defined(ENABLE_ASSERTS)
  #define MY_ASSERT(x) assert(x)
#else
  #define MY_ASSERT(x)
#end

#define MY_UNUSED(x)

#if defined(ENABLE_ASSERTS)
  #define MY_USED_FOR_ASSERTS(x) x
#else
  #define MY_USED_FOR_ASSERTS(x) MY_UNUSED(x)
#end

다음과 같이 사용하십시오.

int myFunc(int myInt, float MY_USED_FOR_ASSERTS(myFloat), char MY_UNUSED(myChar))
{
  MY_ASSERT(myChar < 12.0f);
  return myInt;
}

0

시간이 중요한 코드 세그먼트에 대한 자체 구현이 있습니다. 나는 느리게하기 위해 시간이 중요한 코드를 잠시 연구 해 왔으며이 구현은 내가 최적화 한 시간에 중요한 코드에서 약 2 %를 소비한다는 것을 발견했습니다.

#define UTILITY_UNUSED(exp) (void)(exp)
#define UTILITY_UNUSED2(e0, e1) UTILITY_UNUSED(e0); UTILITY_UNUSED(e1)
#define ASSERT_EQ(v1, v2) { UTILITY_UNUSED2(v1, v2); } (void)0

시간이 중요한 코드는 ASSERT*디버그 목적으로 정의를 사용 했지만 릴리스에서는 명확하게 잘라 냈지만 ...이 코드는 Visual Studio 2015 Update 3다음 에서 조금 더 빠른 코드를 생성하는 것 같습니다 .

#define UTILITY_UNUSED(exp) (void)(false ? (false ? ((void)(exp)) : (void)0) : (void)0)
#define UTILITY_UNUSED2(e0, e1) (void)(false ? (false ? ((void)(e0), (void)(e1)) : (void)0) : (void)0)

그 이유는 이중 false ?표현입니다. 어떻게 든 최대 최적화로 릴리스에서 약간 더 빠른 코드를 생성합니다.

왜 이것이 더 빠른지 모르겠지만 (컴파일러 최적화의 버그로 보임) 적어도 해당 코드 사례에 대한 더 나은 솔루션입니다.

참고 : 여기서 가장 중요한 것은 릴리스에서 위의 주장이나 사용하지 않는 매크로 없이 시간이 중요한 코드가 느려진다는 것 입니다. 즉, 이중 false ?표현식은 놀랍게도 코드를 최적화하는 데 도움이됩니다.


-1

windows.h 는 UNREFERENCED_PARAMETER를 정의합니다 .

#define UNREFERENCED_PARAMETER(P) {(P) = (P);}

따라서 다음과 같이 할 수 있습니다.

#include <windows.h>
#include <stdio.h>
int main(int argc, char **argv) {
  UNREFERENCED_PARAMETER(argc);
  puts(argv[1]);
  return 0;
}

또는 Windows 외부 :

#include <stdio.h>
#define UNREFERENCED_PARAMETER(P) {(P) = (P);}
int main(int argc, char **argv) {
  UNREFERENCED_PARAMETER(argc);
  puts(argv[1]);
  return 0;
}

6
operator=부작용이있을 수 있기 때문에 이것은 매우 좋은 선택이 아닙니다 .
— Tamás Szelei
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.