it-swarm-ko.tech

C ++의 숨겨진 기능?

질문의 "숨겨진 기능"과 관련하여 C++을 좋아하지 않습니까? 내가 그것을 버릴 것이라고 생각했다. C++의 숨겨진 기능은 무엇입니까?

114
Craig H

대부분의 C++ 프로그래머는 삼항 연산자에 익숙합니다.

x = (y < 0) ? 10 : 20;

그러나 그들은 그것이 lvalue로 사용될 수 있다는 것을 인식하지 못합니다.

(a == 0 ? a : b) = 1;

이것은 속기입니다

if (a == 0)
    a = 1;
else
    b = 1;

주의해서 사용하십시오 :-)

308
Ferruccio

오류없이 URI를 C++ 소스에 넣을 수 있습니다. 예를 들면 다음과 같습니다.

void foo() {
    http://stackoverflow.com/
    int bar = 4;

    ...
}
238
Ben

포인터 산술.

C++ 프로그래머는 소개 될 수있는 버그로 인해 포인터를 피하는 것을 선호합니다.

내가 본 것 중 가장 멋진 C++? 아날로그 리터럴

140
Anonymouse

나는 대부분의 게시물에 동의합니다. C++은 다중 패러다임 언어이므로 찾을 수있는 "숨겨진"기능 (모든 비용을 피해야하는 "정의되지 않은 동작"제외)은 시설을 영리하게 사용합니다.

이러한 기능의 대부분은 언어의 내장 기능이 아니라 라이브러리 기반 기능입니다.

가장 중요한 것은 [~ # ~] raii [~ # ~] 이며, C 세계에서 온 C++ 개발자들은 수년 동안 종종 무시합니다. Operator overloading 종종 배열과 같은 동작 (첨자 연산자), 포인터와 같은 연산 (스마트 포인터) 및 빌드와 같은 연산 (매트릭스 곱하기)을 모두 가능하게하는 오해의 소지가 있습니다.

exception 의 사용은 종종 어렵지만 일부 작업에서는 exception safety 사양을 통해 실제로 강력한 코드를 생성 할 수 있습니다. 실패하지 않거나 성공 또는 원래 상태로 되돌릴 수있는 커밋과 같은 기능을 갖습니다).

C++의 "숨겨진"기능 중 가장 유명한 기능은 template metaprogramming 입니다. 런타임 대신 컴파일 타임에 프로그램을 부분적으로 (또는 완전히) 실행할 수 있기 때문입니다. 그러나 이것은 어렵고 템플릿을 사용하기 전에 제대로 파악해야합니다.

다른 것은 C++의 조상, 즉 C 외부에서 "프로그래밍 방식"을 생성하기 위해 다중 패러다임을 사용합니다.

functors 를 사용하면 추가 형식 안전성과 상태 저장을 통해 함수를 시뮬레이션 할 수 있습니다. command 패턴을 사용하면 코드 실행을 지연시킬 수 있습니다. 대부분의 다른 design patterns C++에서 쉽고 공식적으로 구현하여 "공식 C++ 패러다임"목록에 포함되지 않는 대체 코딩 스타일을 생성 할 수 있습니다.

templates 를 사용하면 처음에는 생각하지 않은 것을 포함하여 대부분의 유형에서 작동하는 코드를 생성 할 수 있습니다. 자동화 된 typesafe malloc/realloc/free와 같이 형식 안전성도 높일 수 있습니다. C++ 객체 기능은 실제로 강력하기 때문에 부주의하게 사용하면 위험하지만 dynamic polymorphism 조차 C++에서 정적 버전을 갖습니다. [~ # ~] crtp [~ # ~] .

Scott Meyers의 대부분의 "Effective C++"형 책 또는 Herb Sutter의 "Exceptional C++"형 책은 읽기 쉽고 보물이 많았습니다. C++의 알려 지거나 알려지지 않은 기능에 대한 정보.

내가 선호하는 것 중에는 Java 프로그래머의 머리카락이 공포에서 비롯되어야합니다.) C++에서 객체에 기능을 추가하는 가장 객체 지향적 인 방법은 다음과 같은 이유로 member-function (예 : 클래스 메소드) 대신 비 멤버 비 친구 함수를 통해

  • C++에서 클래스의 인터페이스는 동일한 네임 스페이스의 멤버 함수와 비 멤버 함수입니다.

  • 비 친구 비회원 함수는 내부 클래스에 대한 특권 액세스 권한이 없습니다. 따라서 비회원 비 친구에 멤버 함수를 사용하면 클래스의 캡슐화가 약화됩니다.

숙련 된 개발자라도 놀라지 않을 것입니다.

(출처 : Herb Sutter의 온라인 주 # 84의 온라인 전문가 : http://www.gotw.ca/gotw/084.htm )

119
paercebal

학교 전체에 걸쳐 들어 본 적이 없기 때문에 다소 숨겨져 있다고 생각되는 언어 기능 중 하나는 네임 스페이스 별칭입니다. 부스트 문서에서 예제를 볼 때까지 관심을 끌지 못했습니다. 물론 이제는 표준 C++ 참조에서 찾을 수 있습니다.

namespace fs = boost::filesystem;

fs::path myPath( strPath, fs::native );
118
Jason Mock

for 루프의 초기화 부분에서 변수를 선언 할 수있을뿐만 아니라 클래스와 함수도 선언 할 수 있습니다.

for(struct { int a; float b; } loop = { 1, 2 }; ...; ...) {
    ...
}

그것은 다른 유형의 여러 변수를 허용합니다.

102

배열 연산자는 연관되어 있습니다.

A [8]은 * (A + 8)의 동의어입니다. 덧셈은 연관성이 있으므로 * (8 + A)로 다시 쓸 수 있습니다. 이는 ..... 8 [A]의 동의어입니다.

당신은 유용한 말을하지 않았다 ... :-)

77
Colin Jensen

잘 알려지지 않은 것 중 하나는 공용체도 템플릿 일 수 있다는 것입니다.

template<typename From, typename To>
union union_cast {
    From from;
    To   to;

    union_cast(From from)
        :from(from) { }

    To getTo() const { return to; }
};

또한 생성자와 멤버 함수도 가질 수 있습니다. 상속 (가상 함수 포함)과 관련이있는 것은 없습니다.

73

C++은 표준이며 숨겨진 기능이 없어야합니다 ...

C++은 다중 패러다임 언어이므로 숨겨진 기능이 있다는 데 마지막 돈을 걸 수 있습니다. 많은 것 중 하나의 예 : 템플릿 메타 프로그래밍 . 표준위원회의 어느 누구도 컴파일 타임에 실행되는 Turing-complete sublanguage를 의도하지 않았습니다.

72
Konrad Rudolph

C에서 작동하지 않는 또 다른 숨겨진 기능은 단항 + 운영자. 그것을 사용하여 모든 종류의 것들을 홍보하고 부패시킬 수 있습니다.

열거 형을 정수로 변환

+AnEnumeratorValue

그리고 이전에 열거 유형을 가졌던 열거 자 값에는 이제 값에 맞는 완벽한 정수 유형이 있습니다. 수동으로, 당신은 그 유형을 거의 알지 못할 것입니다! 예를 들어 열거에 과부하 된 연산자를 구현하려는 경우에 필요합니다.

변수에서 값을 얻습니다

클래스 정의를 벗어나지 않고 클래스 내 정적 초기화를 사용하는 클래스를 사용해야하지만 때로는 링크에 실패합니까? 운영자는 유형에 대한 가정 또는 의존성을 만들지 않고 임시를 만드는 데 도움을 줄 수 있습니다.

struct Foo {
  static int const value = 42;
};

// This does something interesting...
template<typename T>
void f(T const&);

int main() {
  // fails to link - tries to get the address of "Foo::value"!
  f(Foo::value);

  // works - pass a temporary value
  f(+Foo::value);
}

포인터를 배열로 결정

함수에 두 개의 포인터를 전달하고 싶지만 작동하지 않습니까? 운영자가 도울 수 있습니다

// This does something interesting...
template<typename T>
void f(T const& a, T const& b);

int main() {
  int a[2];
  int b[3];
  f(a, b); // won't work! different values for "T"!
  f(+a, +b); // works! T is "int*" both time
}
66

Const 참조에 묶인 임시의 수명은 소수의 사람들이 아는 것입니다. 또는 적어도 대부분의 사람들이 모르는 가장 좋아하는 C++ 지식입니다.

const MyClass& x = MyClass(); // temporary exists as long as x is in scope
61
MSN

자주 사용되지 않는 Nice 기능은 함수 전체 try-catch 블록입니다.

int Function()
try
{
   // do something here
   return 42;
}
catch(...)
{
   return -1;
}

주요 사용법은 예외를 다른 예외 클래스로 변환하고 다시 throw하거나 예외와 반환 기반 오류 코드 처리간에 변환하는 것입니다.

52
vividos

많은 사람들이 identity/id 메타 함수를 알고 있지만, 템플릿이 아닌 경우를위한 멋진 사용 사례가 있습니다.

// void (*f)(); // same
id<void()>::type *f;

// void (*f(void(*p)()))(int); // same
id<void(int)>::type *f(id<void()>::type *p);

// int (*p)[2] = new int[10][2]; // same
id<int[2]>::type *p = new int[10][2];

// void (C::*p)(int) = 0; // same
id<void(int)>::type C::*p = 0;

C++ 선언을 크게 해독하는 데 도움이됩니다!

// boost::identity is pretty much the same
template<typename T> 
struct id { typedef T type; };
44

매우 숨겨진 기능은 if 조건 내에서 변수를 정의 할 수 있으며 해당 범위는 if 및 else 블록에만 적용된다는 것입니다.

if(int * p = getPointer()) {
    // do something
}

예를 들어 다음과 같은 일부 "잠금"범위를 제공하기 위해 일부 매크로가이를 사용합니다.

struct MutexLocker { 
    MutexLocker(Mutex&);
    ~MutexLocker(); 
    operator bool() const { return false; } 
private:
    Mutex &m;
};

#define locked(mutex) if(MutexLocker const& lock = MutexLocker(mutex)) {} else 

void someCriticalPath() {
    locked(myLocker) { /* ... */ }
}

또한 BOOST_FOREACH는이를 후드 아래에서 사용합니다. 이를 완료하려면 if뿐만 아니라 스위치에서도 가능합니다.

switch(int value = getIt()) {
    // ...
}

그리고 while 루프에서 :

while(SomeThing t = getSomeThing()) {
    // ...
}

(그리고 또한 조건). 그러나 이것이 모두 유용한 지 여부는 확실하지 않습니다. :)

43

쉼표 연산자가 연산자 오버로드를 호출하지 못하도록 방지

때로는 쉼표 연산자를 유효하게 사용하지만 사용자 정의 쉼표 연산자가 방해가되지 않도록하려는 경우가 있습니다. 예를 들어 왼쪽과 오른쪽 사이의 시퀀스 지점에 의존하거나 원하는 것을 방해하지 않기를 원하기 때문입니다. 동작. 여기서 void()이 게임에 등장합니다 :

for(T i, j; can_continue(i, j); ++i, void(), ++j)
  do_code(i, j);

조건 및 코드에 대해 넣은 자리 표시자를 무시하십시오. 중요한 것은 컴파일러가 내장 된 쉼표 연산자를 사용하도록하는 void()입니다. 이것은 때때로 특성 클래스를 구현할 때 유용 할 수 있습니다.

29

생성자에서 배열 초기화. 예를 들어 int 배열이 다음과 같은 경우 클래스에서 :

class clName
{
  clName();
  int a[10];
};

배열의 모든 요소를 ​​생성자에서 기본값 (여기서 배열의 모든 요소는 0으로)으로 초기화 할 수 있습니다.

clName::clName() : a()
{
}
28
Poorna

우, 대신 애완 동물 모자 목록을 만들 수 있습니다.

  • 다형성을 사용하려는 경우 소멸자는 가상이어야합니다.
  • 때때로 멤버는 기본적으로 초기화되고 때로는 멤버가 아닌 경우
  • 로컬 클래스는 템플릿 매개 변수로 사용할 수 없습니다 (유용하지 않음).
  • 예외 지정자 : 유용 해 보이지만 유용하지는 않습니다.
  • 함수 오버로드는 다른 서명으로 기본 클래스 함수를 숨 깁니다.
  • 국제화에 유용한 표준화가 없습니다 (휴대용 표준 와이드 문자셋, 누군가? C++ 0x까지 기다려야 함)

긍정적 인 측면에서는

  • 숨겨진 기능 : 기능 시도 블록. 불행히도 나는 그것을 사용하지 못했습니다. 예, 왜 그들이 추가했는지 알지만, 그것을 무의미하게 만드는 생성자에서 다시 던져야합니다.
  • 컨테이너 수정 후 반복자 유효성에 대해 STL 보장을주의 깊게 살펴보면 약간 더 멋진 루프를 만들 수 있습니다.
  • 부스트-비밀은 아니지만 거의 가치가 있습니다.
  • 반환 값 최적화 (명확하지는 않지만 표준에서 특별히 허용됨)
  • 함수 (일명 함수 함수, 일명 operator ()) 이것은 STL에서 광범위하게 사용됩니다. 실제로 비밀은 아니지만 연산자 오버로드 및 템플릿의 멋진 부작용입니다.
27
Robert

정의되지 않은 동작없이 예상되는 의미로 모든 클래스의 보호 된 데이터 및 함수 멤버에 액세스 할 수 있습니다. 방법을 보려면 계속 읽으십시오. 이것에 대해 결함 보고서 도 읽으십시오.

일반적으로 C++에서는 클래스가 기본 클래스 인 경우에도 클래스 객체의 비 정적 보호 멤버에 액세스 할 수 없습니다.

struct A {
protected:
    int a;
};

struct B : A {
    // error: can't access protected member
    static int get(A &x) { return x.a; }
};

struct C : A { };

금지되어 있습니다 : 당신과 컴파일러는 참조가 실제로 무엇을 가리키는 지 모릅니다. C 객체 일 수 있습니다.이 경우 B 클래스에는 비즈니스가 없으며 데이터에 대한 단서가 있습니다. x이 파생 클래스 또는 그 파생 클래스에 대한 참조 인 경우에만 이러한 액세스 권한이 부여됩니다. 그리고 임의의 코드 조각으로 보호 된 멤버를 읽을 수 있습니다. 예를 들어 std::stack :

void f(std::stack<int> &s) {
    // now, let's decide to mess with that stack!
    struct pillager : std::stack<int> {
        static std::deque<int> &get(std::stack<int> &s) {
            // error: stack<int>::c is protected
            return s.c;
        }
    };

    // haha, now let's inspect the stack's middle elements!
    std::deque<int> &d = pillager::get(s);
}

확실히, 이것은 당신이 너무 많은 피해를 일으킬 것입니다 참조하십시오. 그러나 이제 멤버 포인터를 사용하면이 보호 기능을 피할 수 있습니다! 요점은 멤버 포인터의 유형이 실제로 해당 멤버를 포함하는 클래스에 바인딩되어 있다는 것입니다.- not 주소. 이를 통해 검사를 우회 할 수 있습니다

struct A {
protected:
    int a;
};

struct B : A {
    // valid: *can* access protected member
    static int get(A &x) { return x.*(&B::a); }
};

struct C : A { };

물론 std::stack 예.

void f(std::stack<int> &s) {
    // now, let's decide to mess with that stack!
    struct pillager : std::stack<int> {
        static std::deque<int> &get(std::stack<int> &s) {
            return s.*(pillager::c);
        }
    };

    // haha, now let's inspect the stack's middle elements!
    std::deque<int> &d = pillager::get(s);
}

파생 클래스에서 using 선언을 사용하면 멤버 이름을 공개하고 기본 클래스의 멤버를 참조하는 것이 훨씬 쉬워집니다.

void f(std::stack<int> &s) {
    // now, let's decide to mess with that stack!
    struct pillager : std::stack<int> {
        using std::stack<int>::c;
    };

    // haha, now let's inspect the stack's middle elements!
    std::deque<int> &d = s.*(&pillager::c);
}
27

숨겨진 기능 :

  1. 순수한 가상 함수는 구현할 수 있습니다. 일반적인 예, 순수한 가상 소멸자.
  2. 함수가 예외 사양에 나열되지 않은 예외를 throw하지만 예외 사양에 std::bad_exception가 있으면 예외는 std::bad_exception로 변환되어 자동으로 throw됩니다. 그렇게하면 최소한 bad_exception가 발생했음을 알 수 있습니다. 더 읽기 여기 .

  3. 기능 시도 블록

  4. 클래스 템플릿에서 명확하게 정의 된 typedef의 템플릿 키워드 ., -> 또는 :: 연산자 뒤에 멤버 템플리트 전문화 이름이 표시되고 해당 이름에 명시 적으로 규정 된 템플리트 매개 변수가있는 경우 멤버 템플리트 이름 앞에 키워드 템플릿. 더 읽기 여기 .

  5. 함수 매개 변수 기본값은 런타임시 변경 될 수 있습니다. 더 읽기 여기 .

  6. A[i]i[A]만큼 잘 작동합니다.

  7. 클래스의 임시 인스턴스를 수정할 수 있습니다! 임시 객체에서 비 const 멤버 함수를 호출 할 수 있습니다. 예를 들면 다음과 같습니다.

    struct Bar {
      void modify() {}
    }
    int main (void) {
      Bar().modify();   /* non-const function invoked on a temporary. */
    }
    

    더 읽기 여기 .

  8. 삼항 (:) 연산자 표현식에서 ?: 전후에 서로 다른 두 유형이있는 경우 결과 유형은 두 유형 중 가장 일반적인 유형입니다. 예를 들면 다음과 같습니다.

    void foo (int) {}
    void foo (double) {}
    struct X {
      X (double d = 0.0) {}
    };
    void foo (X) {} 
    
    int main(void) {
      int i = 1;
      foo(i ? 0 : 0.0); // calls foo(double)
      X x;
      foo(i ? 0.0 : x);  // calls foo(X)
    }
    
26
Sumant

또 다른 숨겨진 기능은 함수 포인터 또는 참조로 변환 될 수있는 클래스 객체를 호출 할 수 있다는 것입니다. 결과에 따라 과부하 해결이 이루어지며 인수가 완벽하게 전달됩니다.

template<typename Func1, typename Func2>
class callable {
  Func1 *m_f1;
  Func2 *m_f2;

public:
  callable(Func1 *f1, Func2 *f2):m_f1(f1), m_f2(f2) { }
  operator Func1*() { return m_f1; }
  operator Func2*() { return m_f2; }
};

void foo(int i) { std::cout << "foo: " << i << std::endl; }
void bar(long il) { std::cout << "bar: " << il << std::endl; }

int main() {
  callable<void(int), void(long)> c(foo, bar);
  c(42); // calls foo
  c(42L); // calls bar
}

이것을 "서로 콜 기능"이라고합니다.

26

map::operator[]는 키가없는 경우 항목을 작성하고 기본 구성 항목 값에 대한 참조를 리턴합니다. 그래서 당신은 쓸 수 있습니다 :

map<int, string> m;
string& s = m[42]; // no need for map::find()
if (s.empty()) { // assuming we never store empty values in m
  s.assign(...);
}
cout << s;

나는 이것을 모르는 C++ 프로그래머의 수에 놀랐다.

24
Constantin

이름없는 네임 스페이스에 함수 나 변수를 넣으면 static를 사용하여 파일 범위로 제한하지 않습니다.

20
Jim Hunziker

클래스 템플릿에서 일반적인 친구 기능을 정의하려면 특별한주의가 필요합니다.

template <typename T> 
class Creator { 
    friend void appear() {  // a new function ::appear(), but it doesn't 
        …                   // exist until Creator is instantiated 
    } 
};
Creator<void> miracle;  // ::appear() is created at this point 
Creator<double> oops;   // ERROR: ::appear() is created a second time! 

이 예에서 두 개의 다른 인스턴스화는 두 개의 동일한 정의를 만듭니다. ODR

따라서 클래스 템플릿의 템플릿 매개 변수가 특정 파일에서 클래스 템플릿의 인스턴스를 두 번 이상 인스턴스화하지 않으려는 경우가 아니라면 해당 템플릿에 정의 된 모든 친구 함수 형식으로 표시되어야합니다. 이것을 이전 예제의 변형에 적용 해 봅시다 :

template <typename T> 
class Creator { 
    friend void feed(Creator<T>*){  // every T generates a different 
        …                           // function ::feed() 
    } 
}; 

Creator<void> one;     // generates ::feed(Creator<void>*) 
Creator<double> two;   // generates ::feed(Creator<double>*) 

면책 조항 : 나는이 섹션을 C++ Templates : The Complete Guide /Section 8.4에서 붙여 넣었습니다.

19
Özgür

void 함수는 void 값을 반환 할 수 있습니다

거의 알려지지 않았지만 다음 코드는 괜찮습니다.

void f() { }
void g() { return f(); }

다음의 이상해 보이는 것만 큼

void f() { return (void)"i'm discarded"; }

이것에 대해 알고 있으면 일부 영역에서 활용할 수 있습니다. 예를 들면 다음과 같습니다. void 함수는 값을 반환 할 수 없지만 비 공백으로 인스턴스화 될 수 있으므로 아무 것도 반환 할 수 없습니다. void에 오류가 발생하는 로컬 변수에 값을 저장하는 대신 직접 값을 반환

template<typename T>
struct sample {
  // assume f<T> may return void
  T dosomething() { return f<T>(); }

  // better than T t = f<T>(); /* ... */ return t; !
};
18

문자열 벡터로 파일을 읽습니다.

 vector<string> V;
 copy(istream_iterator<string>(cin), istream_iterator<string>(),
     back_inserter(V));

istream_iterator

17
Jason Baker

모든 프로그래밍 언어 중에서 가장 흥미로운 문법 중 하나입니다.

이 중 세 가지가 함께 속해 있고 두 가지가 완전히 다른 것입니다.

SomeType t = u;
SomeType t(u);
SomeType t();
SomeType t;
SomeType t(SomeType(u));

세 번째와 다섯 번째를 제외하고 스택에서 SomeType 객체를 정의하고 초기화합니다 (처음 두 경우에는 u, 네 번째 경우에는 기본 생성자 사용). 세 번째는 다음과 같은 함수를 선언합니다. 매개 변수를 사용하지 않고 SomeType을 반환합니다. 다섯 번째는 비슷하게 SomeType이라는 u 유형의 값으로 하나의 매개 변수를 사용하는 함수를 선언합니다.

14
Eclipse

비트 필드를 템플릿 할 수 있습니다.

template <size_t X, size_t Y>
struct bitfield
{
    char left  : X;
    char right : Y;
};

나는 이것에 대한 어떤 목적도 아직 내놓지 않았지만 도대체 나를 놀라게했다.

14
Kaz Dragon

지배 규칙은 유용하지만 거의 알려져 있지 않습니다. 기본 클래스 격자를 통해 고유하지 않은 경로에 있더라도 구성원이 가상 기본 클래스에 속하는 경우 부분적으로 숨겨진 멤버의 이름 조회는 고유합니다.

struct A { void f() { } };

struct B : virtual A { void f() { cout << "B!"; } };
struct C : virtual A { };

// name-lookup sees B::f and A::f, but B::f dominates over A::f !
struct D : B, C { void g() { f(); } };

나는 이것을 지배 규칙에 의해 가장 엄격한 정렬을 자동으로 알아내는 implement alignment-support 에 사용했습니다.

이것은 가상 함수뿐만 아니라 typedef 이름, 정적/비가 상 멤버 및 기타 항목에도 적용됩니다. 메타 프로그램에서 쓸 수있는 특성을 구현합니다.

12

삼항 조건부 연산자 ?:는 두 번째 및 세 번째 피연산자가 "합의 가능한"유형 (비공식적으로 말하기)을 갖도록 요구합니다. 그러나이 요구 사항에는 하나의 예외가 있습니다 (pun 의도 된 것). 두 번째 또는 세 번째 피연산자는 다른 피연산자의 유형에 관계없이 throw 표현식 (void 유형) 일 수 있습니다.

다시 말해, ?: 연산자를 사용하여 다음과 같은 올바른 C++ 표현식을 작성할 수 있습니다.

i = a > b ? a : throw something();

BTW, throw 식은 실제로 expression (void 유형)이고 명령문이 아니라는 사실은 C++ 언어의 잘 알려지지 않은 또 다른 기능입니다. 이것은 무엇보다도 다음 코드가 완벽하게 유효하다는 것을 의미합니다.

void foo()
{
  return throw something();
}

이 방법으로 수행 할 점은별로 없지만 (일부 일반적인 템플릿 코드에서는 유용 할 수 있습니다).

12
AnT

앞으로 선언을 제거 :

struct global
{
     void main()
     {
           a = 1;
           b();
     }
     int a;
     void b(){}
}
singleton;

? : 연산자를 사용하여 스위치 문 작성 :

string result = 
    a==0 ? "zero" :
    a==1 ? "one" :
    a==2 ? "two" :
    0;

한 줄로 모든 것을하는 것 :

void a();
int b();
float c = (a(),b(),1.0f);

Memset이없는 zeroing 구조체 :

FStruct s = {0};

정규화/래핑 각도 및 시간 값 :

int angle = (short)((+180+30)*65536/360) * 360/65536; //==-150

참조 할당 :

struct ref
{
   int& r;
   ref(int& r):r(r){}
};
int b;
ref a(b);
int c;
*(int**)&a = &c;
12
AareP

이 블로그가 C++의 비전에 관한 놀라운 자료라는 것을 알았습니다 : C++ Truths .

9
Drealmer

위험한 비밀은

Fred* f = new(ram) Fred(); http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10
f->~Fred();

내가 가장 좋아하는 비밀은 거의 사용되지 않았다.

class A
{
};

struct B
{
  A a;
  operator A&() { return a; }
};

void func(A a) { }

int main()
{
  A a, c;
  B b;
  a=c;
  func(b); //yeah baby
  a=b; //gotta love this
}
8
user34537

현지 수업은 훌륭합니다.

struct MyAwesomeAbstractClass
{ ... };


template <typename T>
MyAwesomeAbstractClass*
create_awesome(T param)
{
    struct ans : MyAwesomeAbstractClass
    {
        // Make the implementation depend on T
    };

    return new ans(...);
}

쓸모없는 클래스 정의로 네임 스페이스를 오염시키지 않기 때문에 매우 깔끔합니다 ...

8
Alexandre C.

GCC 개발자 에 숨겨져있는 숨겨진 기능 중 하나는 문자열 리터럴을 사용하여 배열 멤버를 초기화하는 것입니다. C 배열과 함께 작동해야하는 구조가 있고 기본 내용으로 배열 멤버를 초기화한다고 가정합니다.

struct Person {
  char name[255];
  Person():name("???") { }
};

이것은 작동하며 char 배열 및 문자열 리터럴 이니셜 라이저에서만 작동합니다. strcpy이 (가) 필요하지 않습니다!

많은 예제 중 하나 : 템플릿 메타 프로그래밍. 표준위원회의 어느 누구도 컴파일 타임에 실행되는 Turing-complete sublanguage를 의도하지 않았습니다.

템플릿 메타 프로그래밍은 숨겨진 기능이 아닙니다. 부스트 라이브러리에도 있습니다. MPL 을 참조하십시오. 그러나 "거의 숨겨진"정도면 충분하다면 boost 라이브러리 를 살펴보십시오. 그것은 강력한 라이브러리의 뒷받침없이 쉽게 접근 할 수없는 많은 것들을 포함합니다.

한 가지 예는 boost.lambda 라이브러리입니다. C++에는 현재 표준에 람다 함수가 없으므로 흥미 롭습니다.

또 다른 예로는 Loki 가 있습니다. "C++ 템플릿 메타 프로그래밍을 광범위하게 사용하고 일반적으로 사용되는 몇 가지 도구 인 typelist, functor, singleton, smart pointer, object factory, visitor 및 multimethods를 구현합니다." [ 위키 백과 ]

6
Markowitch

숨겨진 기능은 없지만 C++ 언어는 매우 강력하며 표준 개발자조차도 C++을 사용할 수있는 것을 상상할 수 없었습니다.

실제로 간단한 언어 구성으로 매우 강력한 무언가를 작성할 수 있습니다. www.boost.org에서 이러한 많은 것들을 예로들 수 있습니다 (및 http://www.boost.org/doc/libs/1_36_0/doc/html/lambda.html ).

간단한 언어 구성을 강력한 언어로 결합하는 방법을 이해하려면 "C++ 템플릿 : 완전한 안내서"(David Vandevoorde, Nicolai M. Josuttis )를 읽고 읽는 것이 좋습니다. 정말 마법의 책 "Andrei Alexandrescu 의 현대 C++ 디자인 ...".

마지막으로 C++을 배우기가 어렵습니다. 채워야합니다.)

5
sergtk

이름없는 네임 스페이스에 대해 아는 사람은 거의 없습니다.

namespace {
  // Classes, functions, and objects here.
}

이름이없는 네임 스페이스는 다음과 같이 교체 된 것처럼 동작합니다.

namespace __unique_{ /* empty body */ }
using namespace __unique_name__;
namespace __unique_{
  // original namespace body
}

".. 여기서 번역 단위에서 [이 고유 이름]의 모든 발생이 동일한 식별자로 대체되고이 식별자가 전체 프로그램의 다른 모든 식별자와 다릅니다." [C++ 03, 7.3.1.1/1]

4
vobject
4
Özgür

나는 숨겨져 있는지 확실하지 않지만 스펙을 읽는 것만으로는 분명하지 않은 관심'tricks' 가 있습니다.

3
dbrien

"정의되지 않은 동작"이 많이 있습니다. 좋은 책을 읽고 표준을 읽는 것을 피하는 방법을 배울 수 있습니다.

3
ugasoft

대부분의 C++ 개발자는 템플릿 메타 프로그래밍의 힘을 무시합니다. Loki Libary 를 확인하십시오. 템플릿 메타 프로그래밍을 광범위하게 사용하여 형식 목록, 펑터, 싱글 톤, 스마트 포인터, 객체 팩토리, 방문자 및 멀티 메서드와 같은 여러 고급 도구를 구현합니다 ( wikipedia ). 대부분의 경우이를 "숨겨진"c ++ 기능으로 간주 할 수 있습니다.

3
Sridhar Iyer

C++ 진실 에서.

동일한 범위에서 동일한 서명을 가진 함수를 정의하므로 다음과 같이 합법입니다.

template<class T> // (a) a base template
void f(T) {
  std::cout << "f(T)\n";
}

template<>
void f<>(int*) { // (b) an explicit specialization
  std::cout << "f(int *) specilization\n";
}

template<class T> // (c) another, overloads (a)
void f(T*) {
  std::cout << "f(T *)\n";
}

template<>
void f<>(int*) { // (d) another identical explicit specialization
  std::cout << "f(int *) another specilization\n";
}
3
Özgür
  • 클래스 메소드에 대한 포인터
  • "typename"키워드
3
shoosh
3
sdcvvc

main ()에는 반환 값이 필요하지 않습니다.

int main(){}

가장 짧은 유효한 C++ 프로그램입니다.

2
Jeffrey Faust

자유 함수 포인터와 멤버 함수 포인터 초기화의 차이점에주의하십시오.

회원 기능 :

struct S
{
 void func(){};
};
int main(){
void (S::*pmf)()=&S::func;//  & is mandatory
}

그리고 자유로운 기능 :

void func(int){}
int main(){
void (*pf)(int)=func; // & is unnecessary it can be &func as well; 
}

이 이중화 덕분에 자유 기능인 스트림 매니퓰레이터를 체인없이 추가 할 수 있습니다.

cout<<hex<<56; //otherwise you would have to write cout<<&hex<<56, not neat.
2
Özgür
  1. 키 값이 이미 존재하면 map::insert(std::pair(key, value));을 덮어 쓰지 않습니다.

  2. 정의 직후 클래스를 인스턴스화 할 수 있습니다 (세미콜론이 없어서이 기능으로 인해 수백 개의 컴파일 오류가 발생했으며 클래스에서 이것을 사용하는 사람을 본 적이 없습니다)

    class MyClass {public: /* code */} myClass;
    
2
Viktor Sehr

C++에는 수많은 "tricky"구문이 있습니다. 가상 상속을 사용하여 봉인/최종 클래스 의 "간단한"구현에서 나옵니다. 그리고 Boost의 MPL ( tutorial )와 같은 꽤 복잡한 "메타 프로그래밍"메타 프로그래밍 구문을 얻으십시오. 발로 자신을 쏠 수있는 가능성은 무한하지만, 잘 관리 된 경우 (예 : 숙련 된 프로그래머) 유지 관리 성 및 성능 측면에서 최고의 유연성을 제공합니다.

1
Amir

클래스와 구조체 클래스 키는 거의 동일합니다. 주요 차이점은 클래스는 기본적으로 멤버 및 기본에 대한 개인 액세스로, 구조체는 기본적으로 public으로 설정된다는 것입니다.

// this is completely valid C++:
class A;
struct A { virtual ~A() = 0; };
class B : public A { public: virtual ~B(); };

// means the exact same as:
struct A;
class A { public: virtual ~A() = 0; };
struct B : A { virtual ~B(); };

// you can't even tell the difference from other code whether 'struct'
// or 'class' was used for A and B

조합은 멤버와 메소드를 가질 수 있으며 구조체와 비슷하게 공개 액세스를 기본값으로합니다.

1
a_m0d

간접 변환 관용구 :

스마트 포인터 클래스를 설계한다고 가정하십시오. 연산자 * 및->를 오버로드하는 것 외에도 스마트 포인터 클래스는 일반적으로 변환 연산자를 부울로 정의합니다.

template <class T>
class Ptr
{
public:
 operator bool() const
 {
  return (rawptr ? true: false);
 }
//..more stuff
private:
 T * rawptr;
};

Bool로 변환하면 클라이언트가 bool 피연산자가 필요한 표현식에 스마트 포인터를 사용할 수 있습니다.

Ptr<int> ptr(new int);
if(ptr ) //calls operator bool()
 cout<<"int value is: "<<*ptr <<endl;
else
 cout<<"empty"<<endl;

또한 bool 로의 암시 적 변환은 다음과 같은 조건부 선언에 필요합니다.

if (shared_ptr<X> px = dynamic_pointer_cast<X>(py))
{
 //we get here only of px isn't empty
} 

아아,이 자동 변환은 환영을받지 못하게하는 문을 엽니 다.

Ptr <int> p1;
Ptr <double> p2;

//surprise #1
cout<<"p1 + p2 = "<< p1+p2 <<endl; 
//prints 0, 1, or 2, although there isn't an overloaded operator+()

Ptr <File> pf;
Ptr <Query> pq; // Query and File are unrelated 

//surprise #2
if(pf==pq) //compares bool values, not pointers! 

해결 방법 : 포인터에서 데이터 멤버 [pMember]로 bool로 변환하여 "간접 변환"관용구를 사용하여 암시 적 변환이 1 개만 수행되므로 위에서 언급 한 예기치 않은 동작을 방지 할 수 있습니다. pMember-> bool 오히려 bool-> something 그밖에.

1
Özgür

Delete () 연산자가 * void 외에 size 인수를 사용하면 기본 클래스가됩니다. 이 크기 인수를 사용하면 올바른 크기를 제거하기 위해 유형의 크기를 확인할 수 있습니다. 여기 Stephen Dewhurst 이 내용에 대해 알려줍니다.

또한 일반적인 1 인수 버전이 아닌 2 인수 버전의 연산자 삭제를 사용했습니다. 이 2 인수 버전은 파생 클래스가 연산자 삭제 구현을 상속 할 것으로 기대하는 기본 클래스에서 자주 사용하는 또 다른 "일반"버전의 멤버 연산자 삭제입니다. 두 번째 인수는 삭제되는 객체의 크기를 포함합니다.이 정보는 종종 사용자 정의 메모리 관리를 구현하는 데 유용합니다.

1
Özgür

나는 재귀 템플릿 섭씨가 꽤 멋지다는 것을 발견했다.

template<class int>
class foo;

template
class foo<0> {
    int* get<0>() { return array; }
    int* array;  
};

template<class int>
class foo<i> : public foo<i-1> {
    int* get<i>() { return array + 1; }  
};

API는 각 값에 대해 하나의 함수 포인터가 필요했기 때문에 포인터를 배열의 다양한 부분으로 반환하는 10-15 개의 함수로 클래스를 생성하는 데 사용했습니다.

즉 재귀를 통해 많은 함수를 생성하도록 컴파일러를 프로그래밍합니다. 파이처럼 쉽습니다. :)

1
Macke

내가 가장 좋아하는 것은 당분간 A = B = C와 같은 문장에 의미가 없다는 것입니다. A의 가치가 기본적으로 결정되지 않은 것.

이것을 생각하십시오 :

class clC
{
public:
   clC& operator=(const clC& other)
   {
      //do some assignment stuff
      return copy(other);
   }
   virtual clC& copy(const clC& other);
}

class clB : public clC
{
public:
  clB() : m_copy()
  {
  }

  clC& copy(const clC& other)
  {
    return m_copy;
  }

private:
  class clInnerB : public clC
  {
  }
  clInnerB m_copy;
}

이제 A는 clB 유형의 객체 이외의 객체에 액세스 할 수없는 유형일 수 있으며 C와 관련이없는 값을 가질 수 있습니다.

0
Rune FS

템플릿에 constraints 추가.

0
Özgür

멤버 포인터와 멤버 포인터 연산자-> *

#include <stdio.h>
struct A { int d; int e() { return d; } };
int main() {
    A* a = new A();
    a->d = 8;
    printf("%d %d\n", a ->* &A::d, (a ->* &A::e)() );
    return 0;
}

메소드의 경우 (a-> * & A :: e) ()는 javascript의 Function.call ()과 조금 다릅니다.

var f = A.e
f.call(a) 

멤버에게는 [] 연산자로 액세스하는 것과 약간 비슷합니다.

a['d']
0
Kamil Szot

일부 컴파일러가있는 명령 행 스위치를 통해 사전 정의 된 모든 매크로를 볼 수 있습니다. 이것은 gcc 및 icc (Intel의 C++ 컴파일러)와 함께 작동합니다.

$ touch empty.cpp
$ g++ -E -dM empty.cpp | sort >gxx-macros.txt
$ icc -E -dM empty.cpp | sort >icx-macros.txt
$ touch empty.c
$ gcc -E -dM empty.c | sort >gcc-macros.txt
$ icc -E -dM empty.c | sort >icc-macros.txt

MSVC의 경우 단일 에 나열됩니다. 그것들은 다른 곳에서도 단일 장소에 문서화 될 수 있지만 위의 명령을 사용하면 정의되고 정의되지 않은 것과 정확하게 무엇을 명확하게 볼 수 있습니다 다른 모든 명령 줄 스위치를 적용한 후 값이 사용됩니다.

(정렬 후) 비교 :

 $ diff gxx-macros.txt icx-macros.txt
 $ diff gxx-macros.txt gcc-macros.txt
 $ diff icx-macros.txt icc-macros.txt
0
Roger Pate
class Empty {};

namespace std {
  // #1 specializing from std namespace is okay under certain circumstances
  template<>
  void swap<Empty>(Empty&, Empty&) {} 
}

/* #2 The following function has no arguments. 
   There is no 'unknown argument list' as we do
   in C.
*/
void my_function() { 
  cout << "whoa! an error\n"; // #3 using can be scoped, as it is in main below
  // and this doesn't affect things outside of that scope
}

int main() {
  using namespace std; /* #4 you can use using in function scopes */
  cout << sizeof(Empty) << "\n"; /* #5 sizeof(Empty) is never 0 */
  /* #6 falling off of main without an explicit return means "return 0;" */
}
0
dirkgently