Kiedy są korzystne makra C++? [zamknięte]

Preprocesor C jest uzasadniony obawą i unikaniem przez społeczność C++. Funkcje in-lined, const i szablony są zwykle bezpieczniejszą i lepszą alternatywą dla #define.

Następujące makro:

#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)  

W żaden sposób nie przewyższa sejfu typu:

inline bool succeeded(int hr) { return hr >= 0; }

Ale makra mają swoje miejsce, proszę wymienić zastosowania, które można znaleźć dla makr, że nie można zrobić bez preprocesora.

Proszę umieścić każdy przypadek użycia w oddzielnej odpowiedzi, aby mógł bądź głosowany i jeśli wiesz, jak osiągnąć jedną z odpowiedzi bez preprocesora wskaż, jak w komentarzach tej odpowiedzi.

Author: Motti, 2008-09-18

30 answers

Jako wrappery dla funkcji debugowania, aby automatycznie przekazać takie rzeczy jak __FILE__, __LINE__, itd:

#ifdef ( DEBUG )
#define M_DebugLog( msg )  std::cout << __FILE__ << ":" << __LINE__ << ": " << msg
#else
#define M_DebugLog( msg )
#endif
 115
Author: Frank Szczerba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-13 20:10:03

Metody muszą być zawsze kompletnym, kompilowalnym kodem; makra mogą być fragmentami kodu. W ten sposób można zdefiniować makro foreach:

#define foreach(list, index) for(index = 0; index < list.size(); index++)

I użyj go tak:

foreach(cookies, i)
    printf("Cookie: %s", cookies[i]);

Od C++11, jest ona zastąpiona przez pętlę opartą na zakresie .

 83
Author: jdmichal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-02 15:10:39

Ochrona pliku nagłówkowego wymaga użycia makr.

Czy są jakieś inne obszary, którewymagają makr ? Nie wiele (jeśli w ogóle).

Czy są jakieś inne sytuacje, które korzystają z makr? Tak!!!

Jedno miejsce, w którym używam makr, to bardzo powtarzalny kod. Na przykład, podczas owijania kodu C++ do użycia z innymi interfejsami (. NET, COM, Python, itp...), Muszę łapać różne rodzaje WYJĄTKÓW. Oto jak to robię:

#define HANDLE_EXCEPTIONS \
catch (::mylib::exception& e) { \
    throw gcnew MyDotNetLib::Exception(e); \
} \
catch (::std::exception& e) { \
    throw gcnew MyDotNetLib::Exception(e, __LINE__, __FILE__); \
} \
catch (...) { \
    throw gcnew MyDotNetLib::UnknownException(__LINE__, __FILE__); \
}

Muszę włożyć te zaczepy do każda funkcja owijania. Zamiast wpisywać za każdym razem pełne bloki catch, wpisuję:

void Foo()
{
    try {
        ::mylib::Foo()
    }
    HANDLE_EXCEPTIONS
}
To również ułatwia konserwację. Jeśli kiedykolwiek będę musiał dodać nowy typ wyjątku, jest tylko jedno miejsce, w którym muszę go dodać.

Są też inne użyteczne przykłady: wiele z nich zawiera makra preprocesora __FILE__ i __LINE__.

W każdym razie, makra są bardzo przydatne, gdy są używane poprawnie. Makra nie są złe - ich niewłaściwe użycie jest złe.

 51
Author: Kevin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-07 07:48:24

Wewnątrz kompilacji warunkowej, aby przezwyciężyć problemy różnic między kompilatorami:

#ifdef ARE_WE_ON_WIN32
#define close(parm1)            _close (parm1)
#define rmdir(parm1)            _rmdir (parm1)
#define mkdir(parm1, parm2)     _mkdir (parm1)
#define access(parm1, parm2)    _access(parm1, parm2)
#define create(parm1, parm2)    _creat (parm1, parm2)
#define unlink(parm1)           _unlink(parm1)
#endif
 49
Author: Andrew Stein,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 20:00:32

W większości:

  1. Include guards
  2. kompilacja warunkowa
  3. raportowanie (predefiniowane makra, takie jak __LINE__ i __FILE__)
  4. (rzadko) powielanie powtarzających się wzorców kodu.
  5. w kodzie twojego konkurenta.
 47
Author: David Thornley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-13 20:12:33

Jeśli chcesz utworzyć ciąg znaków z wyrażenia, najlepszym przykładem na to jest assert (#x zamienia wartość x na łańcuch).

#define ASSERT_THROW(condition) \
if (!(condition)) \
     throw std::exception(#condition " is false");
 36
Author: Motti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-04 13:34:08

Stałe łańcuchowe są czasami lepiej definiowane jako makra, ponieważ można zrobić więcej z literałami łańcuchowymi niż z const char *.

Np. literały ciągów mogą być łatwo konkatenowane .

#define BASE_HKEY "Software\\Microsoft\\Internet Explorer\\"
// Now we can concat with other literals
RegOpenKey(HKEY_CURRENT_USER, BASE_HKEY "Settings", &settings);
RegOpenKey(HKEY_CURRENT_USER, BASE_HKEY "TypedURLs", &URLs);

Jeśli użyto const char *, to do wykonania konkatenacji w trybie runtime musiałaby zostać użyta jakaś Klasa łańcuchowa:

const char* BaseHkey = "Software\\Microsoft\\Internet Explorer\\";
RegOpenKey(HKEY_CURRENT_USER, (string(BaseHkey) + "Settings").c_str(), &settings);
RegOpenKey(HKEY_CURRENT_USER, (string(BaseHkey) + "TypedURLs").c_str(), &URLs);
 27
Author: Motti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-23 07:34:59

Gdy chcesz zmienić przepływ programu(return, break i continue) kod w funkcji zachowuje się inaczej niż kod, który jest faktycznie inlined w funkcji.

#define ASSERT_RETURN(condition, ret_val) \
if (!(condition)) { \
    assert(false && #condition); \
    return ret_val; }

// should really be in a do { } while(false) but that's another discussion.
 24
Author: Motti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-17 15:11:18

Oczywistość obejmuje strażników

#ifndef MYHEADER_H
#define MYHEADER_H

...

#endif
 20
Author: Kena,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 19:53:01

Nie można wykonać zwarcia argumentów wywołania funkcji za pomocą zwykłego wywołania funkcji. Na przykład:

#define andm(a, b) (a) && (b)

bool andf(bool a, bool b) { return a && b; }

andm(x, y) // short circuits the operator so if x is false, y would not be evaluated
andf(x, y) // y will always be evaluated
 17
Author: 1800 INFORMATION,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 20:09:23

Powiedzmy, że zignorujemy oczywiste rzeczy, takie jak osłony nagłówków.

Czasami chcesz wygenerować kod, który musi być skopiowany/wklejony przez precompiler:

#define RAISE_ERROR_STL(p_strMessage)                                          \
do                                                                             \
{                                                                              \
   try                                                                         \
   {                                                                           \
      std::tstringstream strBuffer ;                                           \
      strBuffer << p_strMessage ;                                              \
      strMessage = strBuffer.str() ;                                           \
      raiseSomeAlert(__FILE__, __FUNCSIG__, __LINE__, strBuffer.str().c_str()) \
   }                                                                           \
   catch(...){}                                                                \
   {                                                                           \
   }                                                                           \
}                                                                              \
while(false)

Który umożliwia kodowanie tego:

RAISE_ERROR_STL("Hello... The following values " << i << " and " << j << " are wrong") ;

I może generować komunikaty typu:

Error Raised:
====================================
File : MyFile.cpp, line 225
Function : MyFunction(int, double)
Message : "Hello... The following values 23 and 12 are wrong"

Zauważ, że mieszanie szablonów z makrami może prowadzić do jeszcze lepszych wyników (tzn. automatycznego generowania wartości obok siebie wraz z ich nazwami zmiennych)

Innym razem potrzebujesz pliku__ _ i/lub linia__ _ jakiegoś kodu, na przykład do generowania informacji o debugowaniu. Poniżej znajduje się klasyk dla Visual C++:

#define WRNG_PRIVATE_STR2(z) #z
#define WRNG_PRIVATE_STR1(x) WRNG_PRIVATE_STR2(x)
#define WRNG __FILE__ "("WRNG_PRIVATE_STR1(__LINE__)") : ------------ : "

Jak z następującym kodem:

#pragma message(WRNG "Hello World")

Generuje komunikaty typu:

C:\my_project\my_cpp_file.cpp (225) : ------------ Hello World

Innym razem musisz wygenerować kod używając operatorów konkatenacji # i ##, takich jak generowanie getterów i setterów dla właściwości(jest to dość ograniczone przypadki, poprzez).

Innym razem wygenerujesz Kod niż nie skompilujesz, jeśli zostanie użyty przez funkcję, like:

#define MY_TRY      try{
#define MY_CATCH    } catch(...) {
#define MY_END_TRY  }

Które mogą być używane jako

MY_TRY
   doSomethingDangerous() ;
MY_CATCH
   tryToRecoverEvenWithoutMeaningfullInfo() ;
   damnThoseMacros() ;
MY_END_TRY

(mimo to, widziałem tylko ten rodzaj kodu słusznie używany raz )

[[11]}Ostatni, ale nie mniej ważny, słynny boost::foreach !!!
#include <string>
#include <iostream>
#include <boost/foreach.hpp>

int main()
{
    std::string hello( "Hello, world!" );

    BOOST_FOREACH( char ch, hello )
    {
        std::cout << ch;
    }

    return 0;
}

(uwaga: kod skopiowany / wklejony ze strony głównej boost)

Który jest (IMHO) o wiele lepszy niż std::for_each.

Tak więc, makra są zawsze użyteczne, ponieważ są poza normalnymi regułami kompilatora. Ale uważam, że większość czasu widzę jeden, są one faktycznie pozostałości kodu C nigdy nie przetłumaczone na język C++.

 16
Author: paercebal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-18 20:14:03

Frameworki testów jednostkowych dla C++, takie jak UnitTest++, w dużej mierze obracają się wokół makr preprocesora. Kilka linii kodu testu jednostkowego rozszerza się w hierarchię klas, które nie byłyby zabawne, gdyby pisać ręcznie. Bez czegoś takiego jak UnitTest++ i to jest magia preprocesora, Nie wiem jak można efektywnie pisać testy jednostkowe dla C++.

 16
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-29 19:29:10

Strach przed preprocesorem C jest jak strach przed żarówkami tylko dlatego, że mamy świetlówki. Tak, ten pierwszy może być nieefektywny. Tak, możesz zostać przez nich (dosłownie) spalony. Ale mogą wykonać zadanie, jeśli odpowiednio się tym zajmiesz.

Gdy programujesz systemy wbudowane, C jest jedyną opcją poza asemblerem. Po zaprogramowaniu na pulpicie w C++ , a następnie przejściu na mniejsze, osadzone cele, nauczysz się przestać martwić o "nieelegancjach" tak wielu gołych funkcji C (makra w zestawie) i po prostu stara się dowiedzieć, jak najlepiej i bezpiecznie korzystać z tych funkcji.

Alexander Stepanov says :

Gdy programujemy w C++ nie powinniśmy się wstydzić jego dziedzictwa C, ale zrobić pełne wykorzystanie. Jedyne problemy z C++, a nawet jedyne problemy z C, pojawiają się kiedy same nie są zgodne z własną logiką.

 13
Author: VictorH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-17 15:46:44

Używamy makr __FILE__ i __LINE__ do celów diagnostycznych w bogatym w informacje rzucaniu WYJĄTKÓW, łapaniu i rejestrowaniu, wraz z automatycznymi skanerami plików dziennika w naszej infrastrukturze QA.

Na przykład, makro rzucające OUR_OWN_THROW może być używane z parametrami typu wyjątku i konstruktora dla tego wyjątku, w tym opisem tekstowym. Tak:

OUR_OWN_THROW(InvalidOperationException, (L"Uninitialized foo!"));

To makro rzuci oczywiście wyjątek InvalidOperationException z opisem jako parametrem konstruktora, ale Zapisz również wiadomość do pliku dziennika składającego się z nazwy pliku i numeru linii, w której wystąpił rzut i jego opisu tekstowego. Wyrzucony wyjątek otrzyma identyfikator, który również zostanie zalogowany. Jeśli wyjątek zostanie kiedykolwiek złapany gdzieś indziej w kodzie, zostanie on oznaczony jako taki, a plik dziennika wskaże, że ten konkretny wyjątek został obsłużony i dlatego nie jest prawdopodobną przyczyną awarii, która może być później zalogowana. Nieobsługiwane wyjątki mogą być łatwo odebrane przez nasza zautomatyzowana Infrastruktura QA.

 9
Author: Johann Gerell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 20:05:51

Niektóre bardzo zaawansowane i użyteczne rzeczy mogą być nadal budowane przy użyciu preprocesora( makr), czego nigdy nie byłoby w stanie zrobić przy użyciu "konstrukcji języka c++", w tym szablonów.

Przykłady:

Tworzenie czegoś zarówno identyfikatora C jak i ciągu

Łatwy sposób użycia zmiennych typów enum jako ciąg znaków w C

Boost Preprocessor Metaprogramming

 8
Author: Suma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:18

Czasami używam makr, dzięki czemu mogę definiować informacje w jednym miejscu, ale używam ich na różne sposoby w różnych częściach kodu. Jest tylko trochę zła:)

Na przykład w "field_list.h": {]}

/*
 * List of fields, names and values.
 */
FIELD(EXAMPLE1, "first example", 10)
FIELD(EXAMPLE2, "second example", 96)
FIELD(ANOTHER, "more stuff", 32)
...
#undef FIELD

Wtedy dla publicznego enum można zdefiniować tylko nazwę:

#define FIELD(name, desc, value) FIELD_ ## name,

typedef field_ {

#include "field_list.h"

    FIELD_MAX

} field_en;

I w prywatnej funkcji init wszystkie pola mogą być użyte do wypełnienia tabeli danymi:

#define FIELD(name, desc, value) \
    table[FIELD_ ## name].desc = desc; \
    table[FIELD_ ## name].value = value;

#include "field_list.h"
 7
Author: Andrew Johnson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 20:50:04

Powtórzenie kodu.

Zajrzyj do boost preprocessor library, jest to rodzaj META-META-programowania. W temacie - > motywacja znajdziesz dobry przykład.

 7
Author: Ruggero Turra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-01 23:28:55

Jednym z powszechnych zastosowań jest wykrywanie środowiska kompilacji, dla rozwoju wieloplatformowego można napisać jeden zestaw kodu dla Linuksa, powiedzmy, a inny dla windows, gdy żadna biblioteka wieloplatformowa nie istnieje już dla Twoich celów.

Więc w przykładzie wieloplatformowym mutex może mieć

void lock()
{
    #ifdef WIN32
    EnterCriticalSection(...)
    #endif
    #ifdef POSIX
    pthread_mutex_lock(...)
    #endif
}

Dla funkcji, są one przydatne, gdy chcesz jawnie ignorować bezpieczeństwo typu. Takie jak wiele przykładów powyżej i poniżej do robienia ASSERT. Oczywiście, jak wiele funkcji C / C++ można można strzelać sobie w stopę, ale język daje narzędzia i pozwala zdecydować, co zrobić.

 6
Author: Doug T.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 19:58:12

Coś jak

void debugAssert(bool val, const char* file, int lineNumber);
#define assert(x) debugAssert(x,__FILE__,__LINE__);

Tak, że można na przykład mieć

assert(n == true);

I uzyskaj nazwę pliku źródłowego i numer linii problemu wydrukowany w twoim dzienniku, jeśli N jest false.

Jeśli używasz normalnego wywołania funkcji, takiego jak

void assert(bool val);

Zamiast makra, wszystko, co możesz uzyskać, to numer linii twojej funkcji assert wydrukowany w dzienniku, co byłoby mniej przydatne.

 6
Author: Keshi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 20:03:36
#define ARRAY_SIZE(arr) (sizeof arr / sizeof arr[0])

W przeciwieństwie do 'preferowanego' rozwiązania szablonu omawianego w bieżącym wątku, możesz użyć go jako wyrażenia stałego:

char src[23];
int dest[ARRAY_SIZE(src)];
 4
Author: fizzer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-05 18:53:05

Możesz użyć # defines, aby pomóc w debugowaniu i testowaniu jednostkowym. Na przykład, utwórz specjalne warianty logowania funkcji pamięci i utwórz specjalną memlog_preinclude.h:

#define malloc memlog_malloc
#define calloc memlog calloc
#define free memlog_free

Skompiluj kod używając:

gcc -Imemlog_preinclude.h ...

Link w Twoim memlogu.o do ostatecznego obrazu. Teraz kontrolujesz malloc, itp., być może w celach logowania lub symulowania błędów alokacji dla testów jednostkowych.

 3
Author: Andrew Johnson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 21:03:34

Używam makr do łatwego definiowania WYJĄTKÓW:

DEF_EXCEPTION(RessourceNotFound, "Ressource not found")

Gdzie DEF_EXCEPTION jest

#define DEF_EXCEPTION(A, B) class A : public exception\
  {\
  public:\
    virtual const char* what() const throw()\
    {\
      return B;\
    };\
  }\
 3
Author: MrBeast,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-15 21:13:21

Kompilatory mogą odrzucić żądanie inline.

Makra zawsze będą miały swoje miejsce.

Coś, co uważam za przydatne, to # define DEBUG do śledzenia debugowania - możesz zostawić go 1 podczas debugowania problemu (lub nawet zostawić go włączonego podczas całego cyklu programowania), a następnie wyłączyć go, gdy nadszedł czas na wysyłkę.

 2
Author: unwieldy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 19:54:39

Gdy podejmujesz decyzję w czasie kompilacji nad zachowaniem specyficznym dla kompilatora / systemu operacyjnego / sprzętu.

Pozwala na dostosowanie interfejsu do specyficznych funkcji Comppiler/OS/Hardware.

#if defined(MY_OS1) && defined(MY_HARDWARE1)
#define   MY_ACTION(a,b,c)      doSothing_OS1HW1(a,b,c);}
#elif define(MY_OS1) && defined(MY_HARDWARE2)
#define   MY_ACTION(a,b,c)      doSomthing_OS1HW2(a,b,c);}
#elif define(MY_SUPER_OS)
          /* On this hardware it is a null operation */
#define   MY_ACTION(a,b,c)
#else
#error  "PLEASE DEFINE MY_ACTION() for this Compiler/OS/HArdware configuration"
#endif
 2
Author: Loki Astari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-24 03:14:42

W mojej ostatniej pracy pracowałem nad skanerem antywirusowym. Aby ułatwić mi debugowanie, miałem wiele logowania utknęło w całym miejscu, ale w aplikacji o dużym zapotrzebowaniu jak ta, koszt wywołania funkcji jest po prostu zbyt drogie. Tak więc, wymyśliłem to małe makro, które nadal pozwalało mi włączyć logowanie debugowania w wersji release na stronie klienta, bez kosztów wywołania funkcji sprawdzi flagę debugowania i po prostu wróci bez logowania czegokolwiek, lub jeśli włączona, zrobi to logowanie... Makro zostało zdefiniowane w następujący sposób:

#define dbgmsg(_FORMAT, ...)  if((debugmsg_flag  & 0x00000001) || (debugmsg_flag & 0x80000000))     { log_dbgmsg(_FORMAT, __VA_ARGS__);  }

Ze względu na VA_ARGS w funkcjach dziennika, to był dobry przypadek dla makra takiego jak to.

Wcześniej używałem makra w aplikacji o wysokim poziomie bezpieczeństwa, które musiało powiedzieć użytkownikowi, że nie ma poprawnego dostępu, i powiedzieć mu, jakiej flagi potrzebuje.

Makro(y) zdefiniowane jako:

#define SECURITY_CHECK(lRequiredSecRoles) if(!DoSecurityCheck(lRequiredSecRoles, #lRequiredSecRoles, true)) return
#define SECURITY_CHECK_QUIET(lRequiredSecRoles) (DoSecurityCheck(lRequiredSecRoles, #lRequiredSecRoles, false))

Wtedy moglibyśmy po prostu posypać czekami po całym interfejsie i powiedzielibyśmy ci, które role są dozwolone aby wykonać czynność, którą próbowałeś wykonać, jeśli nie miałeś jeszcze tej roli. Powodem dla dwóch z nich było zwrócenie wartości w niektórych miejscach, a powrót z funkcji void w innych...

SECURITY_CHECK(ROLE_BUSINESS_INFORMATION_STEWARD | ROLE_WORKER_ADMINISTRATOR);

LRESULT CAddPerson1::OnWizardNext() 
{
   if(m_Role.GetItemData(m_Role.GetCurSel()) == parent->ROLE_EMPLOYEE) {
      SECURITY_CHECK(ROLE_WORKER_ADMINISTRATOR | ROLE_BUSINESS_INFORMATION_STEWARD ) -1;
   } else if(m_Role.GetItemData(m_Role.GetCurSel()) == parent->ROLE_CONTINGENT) {
      SECURITY_CHECK(ROLE_CONTINGENT_WORKER_ADMINISTRATOR | ROLE_BUSINESS_INFORMATION_STEWARD | ROLE_WORKER_ADMINISTRATOR) -1;
   }
...

W każdym razie, tak ich używałem i nie jestem pewien, jak można to było pomóc z szablonami... Poza tym staram się ich unikać, chyba że to naprawdę konieczne.

 2
Author: LarryF,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-27 20:02:22

Kolejne makra foreach. T: type, c: container, i: iterator

#define foreach(T, c, i) for(T::iterator i=(c).begin(); i!=(c).end(); ++i)
#define foreach_const(T, c, i) for(T::const_iterator i=(c).begin(); i!=(c).end(); ++i)

Użycie (pojęcie pokazujące, nie prawdziwe):

void MultiplyEveryElementInList(std::list<int>& ints, int mul)
{
    foreach(std::list<int>, ints, i)
        (*i) *= mul;
}

int GetSumOfList(const std::list<int>& ints)
{
    int ret = 0;
    foreach_const(std::list<int>, ints, i)
        ret += *i;
    return ret;
}

Lepsze implementacje dostępne: Google "BOOST_FOREACH"

Dostępne dobre artykuły: Conditional Love: FOREACH Redux (Eric Niebler) http://www.artima.com/cppsource/foreach.html

 2
Author: Notinlist,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-04 11:33:17

Być może użycie makr greates jest w rozwoju niezależnym od platformy. Pomyśl o przypadkach niespójności typu-w przypadku makr możesz po prostu użyć różnych plików nagłówkowych-takich jak: -- WIN_TYPES.H

typedef ...some struct

--POSIX_TYPES.h

typedef ...some another struct

--program.h

#ifdef WIN32
#define TYPES_H "WINTYPES.H"
#else 
#define TYPES_H "POSIX_TYPES.H"
#endif

#include TYPES_H
Moim zdaniem dużo czytelniejsze niż implementacja go w inny sposób.
 2
Author: rkellerm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-18 12:37:15

Wygląda na to, że VA_ARGS zostały wymienione tylko pośrednio:

Podczas pisania generycznego kodu C++03 i potrzebujesz zmiennej liczby (generycznych) parametrów, możesz użyć makra zamiast szablonu.

#define CALL_RETURN_WRAPPER(FnType, FName, ...)          \
  if( FnType theFunction = get_op_from_name(FName) ) {   \
    return theFunction(__VA_ARGS__);                     \
  } else {                                               \
    throw invalid_function_name(FName);                  \
  }                                                      \
/**/

Uwaga: ogólnie rzecz biorąc, nazwa check/throw może być również włączona do hipotetycznej funkcji get_op_from_name. To tylko przykład. Może istnieć inny ogólny kod otaczający wywołanie VA_ARGS.

Gdy otrzymamy wariacyjne szablony z C++11, można rozwiązać ten" poprawnie " za pomocą szablonu.

 2
Author: Martin Ba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-16 12:03:32

Myślę, że ta sztuczka to sprytne użycie preprocesora, którego nie można emulować za pomocą funkcji:

#define COMMENT COMMENT_SLASH(/)
#define COMMENT_SLASH(s) /##s

#if defined _DEBUG
#define DEBUG_ONLY
#else
#define DEBUG_ONLY COMMENT
#endif

Wtedy możesz użyć go tak:

cout <<"Hello, World!" <<endl;
DEBUG_ONLY cout <<"This is outputed only in debug mode" <<endl;

Można również zdefiniować makro RELEASE_ONLY.

 1
Author: Mathieu Pagé,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 20:06:30

Możesz #define stałe w wierszu poleceń kompilatora używając opcji -D lub /D. Jest to często przydatne podczas kompilacji krzyżowej tego samego oprogramowania dla wielu platform, Ponieważ pliki Makefile mogą kontrolować, jakie stałe są zdefiniowane dla każdej platformy.

 1
Author: bk1e,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 03:44:59