Reputation: 5207
I need to implement some db check using macro.
Lets suppose that we have something like this:
#define DB_CHECK(prop, records) bool found = false; \
for(auto i : records) \
if(i.id == prop.id) found = true; break; \
if(!found) PRINT_ERROR("Some error");
And in the code I call it like this:
std::list <RecordClass> recordsList;
std::list <AnotherClass> anotherClassList;
for(auto &i : myDBrecords)
{
DB_CHECK(i, recordsList);
DB_CHECK(i, anotherClassList);
}
For this I get an error for boolean found
initialization.
'found' : redefinition; multiple initialization
Do you have any idea how can I avoid this? Providing another argument for found
in macro?
Upvotes: 0
Views: 141
Reputation: 2158
It is a Compile Error, caused by second call to DB_CHECK macro. It declares "bool found" again in the same scope of visibility. You can solve the problem by enclosing in brackets {}, this will separate the visibility scopes:
#define DB_CHECK(prop, records) {bool found = false; \
for(auto i : records) \
{if(i.id == prop.id) found = true; break;} \
if(!found) PRINT_ERROR("Some error");}
Or by enclosing the calls
for(auto &i : myDBrecords)
{
{DB_CHECK(i, recordsList);}
{DB_CHECK(i, anotherClassList);}
}
Ok, there exists better approach, the template functions, you have much more control over code, variables and flow
template<typename T1, typename T2> void DB_CHECK(T1 prop, T1 records)
{
for(auto i : records) if(i.id == prop.id) return;
PRINT_ERROR("Some error");
}
Upvotes: 4
Reputation: 334
another approach is to use the __COUNTER__
macro to create a unique variable name.
#define TIE_VARIABLE_NAME_IMPL(name, count) name##count
#define TIE_VARIABLE_NAME(name, count) TIE_VARIABLE_NAME_IMPL(name, count)
#define UNIQUE_NAME(name) TIE_VARIABLE_NAME(name, __COUNTER__)
#define DB_CHECK_IMPL(prop, records, unique_found, unique_i) \
{bool unique_found = false; \
for(auto unique_i : records) { \
if(unique_i.id == prop.id){ unique_found = true; break;} } \
if(!unique_found) PRINT_ERROR("Some error");}
#define DB_CHECK(prop, records) DB_CHECK_IMPL(prop, records, UNIQUE_NAME(found), UNIQUE_NAME(i))
I learned about this approach from this library here https://github.com/ned14/outcome/blob/develop/include/outcome/try.hpp#L145
In your case, I see the approach mentioned in the other answer as a simpler solution to your issue, but this is an alternative way to solve the problem and may be useful in other macro implementations where, for whatever reason, creating an additional scope is undesirable.
This approach also avoids shadowing warnings (e.g. -Wshadow
) in this type of scenario:
bool found = false; // user has a variable named `found` in the scope
DB_CHECK(i, recordsList); // we dont shadow the users `found` because we used a unique name
for more info on the counter macro: https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html also I am not sure how widely supported that macro is, but msvc, clang, and gcc all seem to support it.
Upvotes: 0