Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
#define SQR(x) ((x) * (x))
y = SQR(x++);
a[i++] = i;
while (n >= 0)
if (groups[n--] == gid)
#include <stdio.h>
int main(int argc, char **argv)
{
int i;
int n = 10;
int groups[n];
for(i = 0; i < n; i++)
{
groups[i] = i;
}
while (n >= 0)
printf("%d\n", groups[n--]);
}
$ ./test
4195728
9
8
7
6
5
4
3
2
1
0
while (n)
printf("%d\n", groups[--n]);
while (n --> 0)
printf("%d\n", groups[n]);
m << 1, 2, 3,
4, 5, 6,
7, 8, 9;
Здесь запятая в роли оператора (а значит, является точкой следования)Перегруженный оператор запятая (как и операторы || и &&) теряет свои специальные свойства, превращаясь в простой вызов функции. Поэтому, скажем, такой код содержит UB (gcc даже выдает об этом предупреждение):
struct C {};
C& operator,(C& c, int) { return c; }
C c;
int i = 0;
c, i++, i++;
f( f(c, i++), i++);
template<typename ReturnType, class Class, typename... ParameterTypes>
static inline ReturnType safeCall(const ReturnType& defaultValue, Class *ptr, ReturnType (Class::*Method)(ParameterTypes...), ParameterTypes... arguments)
{
if(ptr)
return (ptr->*Method)(std::forward<ParameterTypes>(arguments)...);
return defaultValue;
}
// вызов
auto x = safeCall(defaultRetval, pointer, &Class::method, param);
#define READ_CASE(type) case TYPE_##: dataStream >> _data.f_##type; break
struct variant {
union {
int8_t f_int8_t;
uint8_t f_int8_t;
// ...
} _data;
_type;
}
//..
dataStream >> _type;
switch(_type) {
READ_CASE(bool);
READ_CASE(int8_t);
READ_CASE(uint8_t);
READ_CASE(int16_t);
//..
}
prefix_safeCallVoid(findObject(), method());
prefix_safeCallVoid( std::make_unique<T>(), foo );
prefix_safeCallVoid( std::make_unique<T>(1,2,3), foo );
prefix_safeCallVoid( createObject(), add_to_list(pool) );
Если уж создавать подобный макрос, то нужно гарантировать, что аргументы гарантированно используются ровно 1 раз
или что лучше — написать шаблонный метод.
У шаблонного метода мне не нравится то, что нужно передавать указатель на метод.Минусом работы через указатель на метод является то, что отваливаются аргументы по умолчанию для данного метода. Этого можно избежать, передавая вместо указателя функциональный объект вида:
[&](auto&& ptr){ return ptr->some_func(...); }
но синтаксис будет уже слегка многословным.do { ... } while (false) (которая ещё и не даёт вернуть из неё значение) позволяют развернуть макрос в определение функции и её последующий вызов с нужными аргументами:#define safeCall(defaultValue, objectPointer, methodWithArguments) \
[](auto&& ptr){ \
return ptr ? (ptr->methodWithArguments) : (defaultValue); \
} /* define function */ \
(objectPointer) /* and call */
struct Test {
int test(int value) { return value; }
};
int main()
{
Test* ptr1 = nullptr;
Test* ptr2 = new Test;
cout << safeCall(0, ptr1, test(10)) << ' ' << safeCall(0, ptr2, test(10));
}
#define safeCall(defaultValue, objectPointer, methodWithArguments)\
[&](const decltype(defaultValue)& defaultRetval, const decltype(objectPointer) pointer)\
{\
return pointer ? (pointer->methodWithArguments) : defaultRetval;\
}\
(defaultValue, objectPointer)
struct Test {
int test(int value) { return value; }
};
int main(int argc, const char* argv[])
{
Test* ptr1 = nullptr;
Test* ptr2 = new Test;
auto def = 0;
int param = 20;
if(0 == safeCall(def, ptr1, test(param)))
std::cout << safeCall(0, ptr2, test(param)) << std::endl;
return 0;
}
((defaultValue), (objectPointer))
#define safeCallVoid(objectPointer, methodWithArguments)\
[&](const decltype(objectPointer) pointer)\
{\
if(pointer)\
(pointer->methodWithArguments);\
}\
(objectPointer)
auto в списке параметров разрешены только в С++14 (компилировать надо с опцией -std=c++1y). В вашем коде несколько косяков:[&] — не нужен, т.к. вы ничего не захватываете на самом деле.const decltype(defaultValue)& — сразу несколько проблем. Самое очевидное — значение по умолчанию вычисляется в любом случае, независимо от того нулевой указатель или нет. Во-вторых, оно насильно сделано const lvalue, поэтому если у типа, который мы возвращаем, нету конструктора копирования (а есть только перемещения), то ваш код не компилируется:struct Fail {
unique_ptr<int> get_ptr() { return unique_ptr<int>(new int); }
};
safeCall(unique_ptr<int>{}, new Fail, get_ptr());
if и два return.const decltype(objectPointer) pointer — в некоторых случаях эта конструкция развернется в приём указателя по значению. В случае встроенных указателей ничего страшного в этом нет, но smart pointer'ы работать перестанут:unique_ptr<Test> ptr;
safeCall(0, ptr, test(10));
#define prefix_safeCallVoid(objectPointer, methodWithArguments)\
[&, pointer = objectPointer]()\
{\
if(pointer)\
(pointer->methodWithArguments);\
}\
()
auto&&.[&ref = ...]
int main()
{
struct T {
T() { cout << "Begin lifetime\n"; }
~T() { cout << "End lifetime\n"; };
};
using CT = const T;
auto f = [&x = CT{}, y = CT{}](){};
cout << "----\n";
}
показывает, что временный объект даже до конца выражения не доживает.#define PRINT(A)\
std::cout << #A << " = [" << (A) << "]\n";
inline std::string location(const std::string& file, int line) {
std::ostringstream oss;
oss << file << ": " << line;
return oss.str();
}
#define MY_LOCATION location(__FILE__, __LINE__)
// The arraysize(arr) macro returns the # of elements in an array arr.
// The expression is a compile-time constant, and therefore can be
// used in defining new arrays, for example. If you use arraysize on
// a pointer by mistake, you will get a compile-time error.
//
// One caveat is that arraysize() doesn't accept any array of an
// anonymous type or a type defined inside a function. In these rare
// cases, you have to use the unsafe ARRAYSIZE() macro below. This is
// due to a limitation in C++'s template system. The limitation might
// eventually be removed, but it hasn't happened yet.
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
// use its type.
template <typename T, size_t N>
char (&ArraySizeHelper(T (&array)[N]))[N];
// That gcc wants both of these prototypes seems mysterious. VC, for
// its part, can't decide which to use (another mystery). Matching of
// template overloads: the final frontier.
#ifndef _MSC_VER
template <typename T, size_t N>
char (&ArraySizeHelper(const T (&array)[N]))[N];
#endif
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
Грязные трюки с макросами C++