Скрытые функции C++? [закрытый]

Я использовал jruby, в моем случае я создал в config / initializers

postgres_driver.rb

$CLASSPATH << '~/.rbenv/versions/jruby-1.7.17/lib/ruby/gems/shared/gems/jdbc-postgres-9.4.1200/lib/postgresql-9.4-1200.jdbc4.jar'

или везде, где ваш драйвер, и все!

114
задан 5 revs, 4 users 100% 9 September 2009 в 23:44
поделиться

64 ответа

Большинство программистов на C++ знакомо с тернарным оператором:

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

Однако они не понимают, что это может использоваться в качестве lvalue:

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

, который является стенографией для

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

Использование с осторожностью:-)

308
ответ дан 2 revs 24 November 2019 в 02:28
поделиться

Можно поместить URIs в источник C++ без ошибки. Например:

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

    ...
}
239
ответ дан Ben 24 November 2019 в 02:28
поделиться

Адресная арифметика с указателями.

программисты на C++ предпочитают избегать указателей из-за ошибок, которые могут быть представлены.

самый прохладный C++ я когда-либо видел хотя? Аналоговые литералы.

140
ответ дан 3 revs, 3 users 88%Anonymouse 24 November 2019 в 02:28
поделиться

Я соглашаюсь с большинством сообщений там: C++ является языком мультипарадигмы, таким образом, "скрытыми" функциями, которые Вы найдете (кроме "неопределенных поведений", которых необходимо избежать по всей стоимости) является умное использование средств.

большинство тех средств не является сборкой - в функциях языка, но основанных на библиотеке.

самое важное RAII, часто игнорируемый в течение многих лет разработчиками C++, происходящими из мира C. Оператор, перегружающийся , часто является недооцененной функцией, которые включают оба подобных массиву поведения (нижний оператор), указатель как операции (интеллектуальные указатели) и подобные сборке операции (умножающий матрицы.

использование [1 121] исключение является часто трудным, но с некоторой работой, может произвести действительно устойчивый код до [1 122] безопасность исключения спецификации (включая код, который не перестанет работать, или это будет иметь подобные фиксации функции, который является, это успешно выполнится или вернется назад к его исходному состоянию).

самая известная из "скрытой" функции C++ шаблонное метапрограммирование , поскольку это позволяет Вам иметь свою программу частично (или полностью) выполняемый во время компиляции вместо времени выполнения. Это трудно, тем не менее, и у Вас должно быть твердое схватывание на шаблонах прежде, чем попробовать его.

Другой делать использование нескольких парадигмой для создания "способов запрограммировать" за пределами предка C++, то есть, C.

При помощи [1 124] функторы , можно моделировать функции с дополнительной безопасностью типов и быть с сохранением информации. Используя шаблон команды , можно задержать выполнение кода. Большинство другой шаблоны разработки могут быть легко и эффективно реализованы в C++ для создания альтернативных стилей кодирования, которые, как не предполагают, были в списке "официальных парадигм C++".

При помощи [1 127] шаблоны , можно произвести код, который будет работать над большинством типов, включая не тот, который Вы думали сначала. Можно увеличить безопасность типов, также (как автоматизированный безопасный с точки зрения типов malloc/realloc/free). Функции объекта C++ действительно мощны (и таким образом, опасны, если используется небрежно), но даже динамический полиморфизм имеет свою статическую версию в C++: CRTP.

я нашел, что большинство" Эффективный C++ " - вводит книги от Scott Meyers или" Исключительный C++ " - книги типа от Herb Sutter, чтобы быть и легким читать, и вполне сокровища информации об известных и менее известных функциях C++.

Среди моего предпочтительного тот, который должен сделать волосы из любого повышения программиста Java от ужаса: В C++ самым объектно-ориентированным способом добавить опцию к объекту является через недруга лица, не являющегося членом какой-либо организации, функция, вместо функции членства (т.е. метод класса), потому что:

  • В C++, интерфейс класса является и своими функциями членства и функциями лица, не являющегося членом какой-либо организации, в том же недруге пространства имен

  • , функции лица, не являющегося членом какой-либо организации, не имеют никакого привилегированного доступа к внутреннему классу. По сути, с помощью функции членства по недругу лица, не являющегося членом какой-либо организации, каждый ослабит инкапсуляцию класса.

Это удивляет даже опытных разработчиков.

(Источник: Среди других, Гуру Herb Sutter онлайн Недели № 84: http://www.gotw.ca/gotw/084.htm )

119
ответ дан 6 revs, 3 users 93% 24 November 2019 в 02:28
поделиться

Одной функцией языка, которую я считаю несколько скрытыми, потому что я никогда не слышал об этом в течение моего всего времени в школе, является псевдоним пространства имен. На это не обратили мое внимание, пока я не столкнулся с примерами его в документации повышения. Конечно, теперь, когда я знаю об этом, можно найти его в любой стандартной ссылке C++.

namespace fs = boost::filesystem;

fs::path myPath( strPath, fs::native );
118
ответ дан Jason Mock 24 November 2019 в 02:28
поделиться

Оператор массива ассоциативен.

А [8] является синонимом для * (+ 8). Так как дополнение ассоциативно, который может быть переписан как * (8 + A), который является синонимом для..... 8

Вы не сказали полезный...:-)

77
ответ дан Colin Jensen 24 November 2019 в 02:28
поделиться

Одна вещь это мало известно, состоит в том, что объединения могут быть шаблонами также:

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

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

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

И у них могут быть конструкторы и функции членства также. Просто ничто, что имеет отношение к наследованию (включая виртуальные функции).

73
ответ дан 2 revs 24 November 2019 в 02:28
поделиться

C++ является стандартом, не должно быть никаких скрытых функций...

C++ является языком мультипарадигмы, можно поставить последние деньги там будучи скрытыми функциями. Один пример из многих: шаблонное метапрограммирование . Никто в комитете по стандартам не намеревался там быть полным по Тьюрингу подъязыком, который выполняется во время компиляции.

72
ответ дан Konrad Rudolph 24 November 2019 в 02:28
поделиться

Время жизни временных файлов, связанных со ссылками константы, является тем, о котором знают немного людей. Или по крайней мере это - моя любимая часть знания C++, что большинство людей не знает о.

const MyClass& x = MyClass(); // temporary exists as long as x is in scope
61
ответ дан 3 revs, 3 users 57% 24 November 2019 в 02:28
поделиться

Хорошей функцией, которая не используется часто, является блок try-catch всей функции:

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

Основное использование должно было бы перевести исключение в другой класс исключений и перебросок, или переводить между исключениями и основанной на возврате обработкой кода ошибки.

52
ответ дан vividos 24 November 2019 в 02:28
поделиться

Довольно скрытая функция - то, что можно определить переменные в, если условие и его объем еще охватят только по если, и блоки:

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 использует его под капотом. Для завершения этого это не только возможно в если, но также и в переключателе:

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

и в некоторое время цикле:

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

(и также в для условия). Но я не слишком уверен, являются ли они всем этим полезным:)

43
ответ дан 3 revs 24 November 2019 в 02:28
поделиться

Инициализация массива в конструкторе. Например, в классе, если у нас есть массив int как:

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

Мы можем инициализировать все элементы в массиве к его значению по умолчанию (здесь все элементы массива для обнуления) в конструкторе как:

clName::clName() : a()
{
}
28
ответ дан 3 revs, 3 users 65% 24 November 2019 в 02:28
поделиться

Считайте файл в вектор строк:

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

istream_iterator

17
ответ дан Jason Baker 24 November 2019 в 02:28
поделиться

Скрытые функции:

  1. Чистые виртуальные функции могут иметь реализацию. Типичный пример, чистый виртуальный деструктор.
  2. , Если функция выдает исключение, не перечисленное в его спецификациях исключения, но функция имеет std::bad_exception в его спецификации исключения, исключение преобразовывается в std::bad_exception и выдается автоматически. Тем путем Вы будете, по крайней мере, знать, что bad_exception был брошен. Read больше здесь .

  3. функция пробуют блоки

  4. шаблонное ключевое слово в устранении неоднозначности определений типов в шаблоне класса. Если название членской шаблонной специализации появляется после ., ->, или :: оператор и то имя явно квалифицировали шаблонные параметры, снабдите префиксом членское шаблонное имя шаблон ключевого слова. Read больше здесь .

  5. значения по умолчанию параметра функции могут быть изменены во времени выполнения. Read больше здесь .

  6. A[i] работы, столь же хорошие как i[A]

  7. , Временные экземпляры класса могут быть изменены! Функция членства неконстанты может быть вызвана на временный объект. Например:

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

    Read больше здесь .

  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
ответ дан 5 revs, 3 users 64% 24 November 2019 в 02:28
поделиться

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 24 November 2019 в 02:28
поделиться

Помещение функций или переменных в неназванном пространстве имен удерживает от использования использование static для ограничения их объемом файла.

20
ответ дан Jim Hunziker 24 November 2019 в 02:28
поделиться

Для определения обычного друга функции в шаблонах классов нужно особое внимание:

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! 

В этом примере, два различных инстанцирования создают два идентичных definitions— прямое нарушение 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++: полное руководство / Раздел 8.4

19
ответ дан Özgür 24 November 2019 в 02:28
поделиться

Oooh, я могу придумать список главных объектов неприязни вместо этого:

  • Деструкторы должны быть виртуальными, если Вы предназначаете использование полиморфно
  • Иногда, участники инициализируются по умолчанию, иногда они не
  • , Локальные классы не могут использоваться в качестве шаблонных параметров (делает их менее полезными)
  • спецификаторы исключения: выглядите полезными, но не
  • , функциональные перегрузки скрывают функции базового класса с различными подписями.
  • никакая полезная стандартизация на интернационализации (портативный стандартный широкий набор символов, кто-либо? Мы должны будем ожидать до C++ 0x)

Зато

  • скрытая функция: функционируйте блоки попытки. К сожалению, я не нашел использование для него. Да я знаю, почему они добавили его, но необходимо повторно бросить в конструктора, который делает его бессмысленным.
  • стоит посмотреть тщательно на гарантии STL о законности итератора после контейнерной модификации, которая может позволить Вам сделать некоторые немного более хорошие циклы.
  • Повышение - это - едва секрет, но это стоит использовать.
  • оптимизация Возвращаемого значения (не очевидный, но это конкретно позволяется стандартом)
  • Функторы иначе функциональные объекты иначе оператор (). Это используется экстенсивно STL. не действительно секрет, но изящный побочный эффект перегрузки оператора и шаблонов.
27
ответ дан 3 revs 24 November 2019 в 02:28
поделиться

Одна из самых интересных грамматик любых языков программирования.

Три из этих вещей принадлежат вместе, и два что-то в целом различное...

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

Все кроме третьего и пятого определяют SomeType объект на стеке и инициализируют его (с u в первых двух случаях и конструкторе по умолчанию в четвертом. Третье объявляет функцию, которая не берет параметров и возвращается SomeType. Пятое так же объявляет функцию, которая берет один параметр значением типа SomeType, названного u.

14
ответ дан 2 revs, 2 users 80% 24 November 2019 в 02:28
поделиться

Избавление от предописаний:

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:

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
ответ дан 3 revs 24 November 2019 в 02:28
поделиться

Не только переменные могут быть объявлен в части init цикла for , а также классы и функции.

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

Это позволяет использовать несколько переменных разных типов.

102
ответ дан 24 November 2019 в 02:28
поделиться

Вы можете получить доступ к защищенным данным и функциям любого класса без неопределенного поведения и с ожидаемой семантикой. Прочтите, чтобы узнать, как это сделать. Прочтите также отчет о дефекте об этом.

Обычно 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);
}

Конечно, как вы видите, это нанесет слишком большой урон. Но теперь указатели на элементы позволяют обойти эту защиту! Ключевым моментом является то, что тип указателя на член привязан к классу, который фактически содержит указанный член - , а не к классу, который вы указали при получении адреса. Это позволяет нам обойти проверку

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
ответ дан 24 November 2019 в 02:28
поделиться

Многие знают о метафункции 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
ответ дан 24 November 2019 в 02:28
поделиться

Вы можете использовать шаблоны битовых полей.

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

Я еще не придумал какой-либо цели для этого, но это, черт возьми, меня удивило.

14
ответ дан 24 November 2019 в 02:28
поделиться

Запрещение оператору запятой вызывать перегрузки оператора

Иногда вы правильно используете оператор запятой, но вы хотите, чтобы ни один пользовательский оператор запятой не получил в пути, потому что, например, вы полагаетесь на точки последовательности между левой и правой стороной или хотите убедиться, что ничто не мешает желаемому действию. Здесь в игру вступает void () :

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

Игнорируйте заполнители, которые я поставил для условия и кода. Что важно, так это void () , которая заставляет компилятор использовать встроенный оператор запятой. Иногда это может быть полезно при реализации классов свойств.

29
ответ дан 24 November 2019 в 02:28
поделиться

функции 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
ответ дан 24 November 2019 в 02:28
поделиться

Тернарный условный оператор ?: требует, чтобы его второй и третий операнды имели "согласованные" типы (говоря неформально). Но у этого требования есть одно исключение (каламбур, конечно): либо второй, либо третий операнд может быть выражением throw (которое имеет тип void), независимо от типа другого операнда.

Другими словами, с помощью оператора ?: можно написать следующие вполне корректные выражения языка C++

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

BTW, тот факт, что выражение throw на самом деле является выражением (типа void), а не оператором, является еще одной малоизвестной особенностью языка C++. Это означает, в частности, что следующий код вполне корректен

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

, хотя смысла в нем не так много (возможно, в каком-то общем шаблонном коде это может пригодиться).

12
ответ дан 24 November 2019 в 02:28
поделиться

Другой скрытой особенностью является то, что вы можете вызывать объекты класса, которые могут быть преобразованы в указатели на функции или ссылки. Разрешение перегрузки выполняется на основе их результата, и аргументы передаются безупречно.

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
ответ дан 24 November 2019 в 02:28
поделиться

Еще одна скрытая возможность, которая не работает в 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
ответ дан 24 November 2019 в 02:28
поделиться

Правило доминирования полезно, но малоизвестно. В нем говорится, что даже если в неуникальном пути через решетку базового класса, поиск по имени для частично скрытого члена будет уникальным, если член принадлежит виртуальному базовому классу:

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(); } };

Я использовал это для реализует поддержку выравнивания , которая автоматически определяет строжайшее выравнивание с помощью правила доминирования.

Это относится не только к виртуальным функциям, но и к именам typedef, статическим / невиртуальным членам и всему остальному. Я видел, как он используется для реализации перезаписываемых свойств в метапрограммах.

12
ответ дан 24 November 2019 в 02:28
поделиться