Implementing compile-time mechanism checking uniqueness of a string - c++

The simplest way of defining my problem is that I'm trying to implement a mechanism that would check whether the same string had already been used (or a pair (number, string)). I would like this mechanism to be implemented in a smart way using C preprocessor. I would also like that this mechanism gave me compile errors when there is a conflict or run-time errors in Debug mode (by checking assertions). We don't want the developer to make a mistake when adding a message, as every message should be unique. I know that it could be done by calculating a hash or for example crc/md5 but this mechanism would be conflict-vulnerable which I need to avoid. It is crucial that every message can be used only once.
Example behaviour of this mechanism:
addMessage(1, "Message1") //OK
addMessage(2, "Message2") //OK
.
.
.
addMessage(N, "MessageN") //OK
addMessage(2, "Message2") //Compile error, Message2 has already been used
Alternative behaviour (when Debugging code):
addMessage(1, "Message1") //OK
addMessage(2, "Message2") //OK
.
.
.
addMessage(N, "MessageN") //OK
addMessage(2, "Message2") //Assertion failed, because Message2 has already been used
The preferred way of doing it would be smart usage of #define and #undef directives. In general the preprocessor should be used in a smart way (I am not sure if this is possible) maybe it can be achieved by appropriate combinations of macros? Any C preprocessor hacker that could help me solve this problem?
//EDIT: I need those messages to be unique globally, not only inside one code block (like function of if-statement).
//EDIT2: The best description of the problem would be that I have 100 different source files and I would like to check with a preprocessor (or possibly other mechanism other than parsing source files with a script at a start of the compilation every-time, which would be very time-consuming and would add another stage to an enough complicated project) if a string (or a preprocessor definition) was used more than one time. I still have no idea how to do it (I know it may not be possible at all but I hope it actually is).

This will give an error on duplicate strings:
constexpr bool isequal(char const *one, char const *two) {
return (*one && *two) ? (*one == *two && isequal(one + 1, two + 1))
: (!*one && !*two);
}
constexpr bool isunique(const char *test, const char* const* list)
{
return *list == 0 || !isequal(test, *list) && isunique(test, list + 1);
}
constexpr int no_duplicates(const char* const* list, int idx)
{
return *list == 0 ? -1 : (isunique(*list, list + 1) ? no_duplicates(list + 1, idx + 1) : idx);
}
template <int V1, int V2> struct assert_equality
{
static const char not_equal_warning = V1 + V2 + 1000;
};
template <int V> struct assert_equality<V, V>
{
static const bool not_equal_warning = 0;
};
constexpr const char* l[] = {"aa", "bb", "aa", 0};
static_assert(assert_equality<no_duplicates(l, 0), -1>::not_equal_warning == 0, "duplicates found");
Output from g++:
g++ -std=c++11 unique.cpp
unique.cpp: In instantiation of ‘const char assert_equality<0, -1>::not_equal_warning’:
unique.cpp:29:57: required from here
unique.cpp:20:53: warning: overflow in implicit constant conversion [-Woverflow]
unique.cpp:29:1: error: static assertion failed: duplicates found
The first template parameter (in this case 0) to 'assert_equality' tells you the fist position of a duplicate string.

I am not sure that it is easily doable using the standard C++ preprocessor (I guess that it is not). You might use some other preprocessor (e.g. GPP)
You could make it the other way: generate some X-macro "header" file from some other source (using e.g. a tiny awk script, which would verify the unicity). Then customize your build (e.g. add some rules to your Makefile) to run that generating script to produce the header file.
Alternatively, if you insist that processing being done inside the compiler, and if your compiler is a recent GCC, consider customizing GCC with MELT (e.g. by adding appropriate builtins or pragmas doing the job).
In the previous century, I hacked a small Emacs function to do a similar job (uniquely numbering error messages) within the emacs editor (renumbering some #define-s before saving the C file).

I am going to assume that something like this will work:
addMessage(1, "Message1")
addMessage(2, "Message1")
Or:
addMessage(1, "Message") /* transforms into "Message_1" */
addMessage(2, "Message_1") /* transforms into "Message_1_2" */
Because the C preprocessor expands tokens lazily and prohibits defining a macro from within another macro, it is impossible to save the results of executing one macro so that another macro can make use of it.
On the other hand, it is definitely possible to force uniqueness of symbols:
#define addMessage(N, MSG) const char *_error_message_##N (void) { return MSG; }
Or:
#define addMessage(N, MSG) const char *_error_message_##N (void) { return MSG "_" #N; }
Because during the link step, duplicate symbols with the name _error_message_NUMBER will trigger an error. And because it is a function, it cannot be used inside of another function without triggering an error.

Assuming your compiler is still not C++11 compliant as you have not tagged appropiately. I am also assuming that you are not particular about the Error Message, its just that you want it to work. In which case, the following Macro Based Solution might work for you
#include <iostream>
#include <string>
#define ADD_MESSAGE(N, MSG) \
char * MSG; \
addMessage(N, #MSG);
void addMessage(int n, std::string msg)
{
std::cout << msg << std::endl;
}
int main() {
ADD_MESSAGE(1, Message1); //OK
ADD_MESSAGE(2, Message2); //OK
ADD_MESSAGE(3, MessageN); //OK
ADD_MESSAGE(4, Message2); //Compile error, Message2 has already been used
};
Compile Output
prog.cpp: In function ‘int main()’:
prog.cpp:17:17: error: redeclaration of ‘char* Message2’
ADD_MESSAGE(4, Message2); //Compile error, Message2 has already been used
^
prog.cpp:4:8: note: in definition of macro ‘ADD_MESSAGE’
char * MSG; \
^
prog.cpp:15:17: error: ‘char* Message2’ previously declared here
ADD_MESSAGE(2, Message2); //OK
^
prog.cpp:4:8: note: in definition of macro ‘ADD_MESSAGE’
char * MSG; \
^

If you don't care about large amounts of useless boiler plate then here's one that's entirely the preprocessor, so no worries about scope, and then checks that they are unique at program startup.
In a file:
#ifndef ERROR1
#define ERROR1 "1"
#endif
#ifndef ERROR2
#define ERROR2 "2"
#endif
...
#ifndef ERROR255
#define ERROR255 "255"
#endif
#include <assert.h>
#include <set>
#include <string>
class CheckUnique {
CheckUnique() {
std::set<std::string> s;
static const char *messages = {
#if HAVE_BOOST
# include <boost/preprocessor.hpp>
# define BOOST_PP_LOCAL_LIMITS (1, 254)
# define BOOST_PP_LOCAL_MACRO(N) ERROR ## N,
# include BOOST_PP_LOCAL_ITERATE()
#else // HAVE_BOOST
ERROR1,
ERROR2,
...
#endif // HAVE_BOOST
ERROR255
};
for (int i = 0; i < sizeof messages / sizeof *messages; i++) {
if (s.count(messages[i]))
assert(! "I found two error messages that were the same");
else
s.insert(messages[i]);
}
}
};
static CheckUnique check;
This file can then be #included at the end of each source file, or you can place it into a file of its own and include every single file that has a #define ERROR line in it. That way, as soon as the operating system loads the program, the constructor for check will run and throw the exception.
This also requires you to have access to the Boost.Preprocessor library (and it's header only so it's pretty easy to set up). Although if you can't use that, then you can just hard code the error macros as I have shown with the #if HAVE_BOOST block.
Most of the boiler plate here is pretty simple, so if you generated it with a program (like some sort of portable script) then it would make your life far easier, but it can still be done all in one shot.

Related

Getting around compound literals in C++ to removing the warning

I'm working with libsystemd-dev (a C library) in my C++ application.
I get a gcc/clang pedantic warning
compound literals are a C99-specific feature
with this code:
#include <systemd/sd-bus.h>
void foo()
{
sd_bus_error err = SD_BUS_ERROR_NULL; // compound literals are a C99-specific feature
...
}
Looking at the <systemd/sd-bus.h> header file, I see:
typedef struct {
const char *name;
const char *message;
int _need_free;
} sd_bus_error;
#define SD_BUS_ERROR_MAKE_CONST(name, message) ((const sd_bus_error) {(name), (message), 0})
#define SD_BUS_ERROR_NULL SD_BUS_ERROR_MAKE_CONST(NULL, NULL)
This means I can solve the warning with:
#include <systemd/sd-bus.h>
void foo()
{
sd_bus_error err = {nullptr, nullptr, 0};
...
}
But is that a good idea? If the library changes, my code would need to change too so I feel that it's volatile. Is there really any problem with this warning? Is there a better way to get around it?
There is always the method of just using compiler flags to disable the warning, but I was wondering if there could be an encouraged method in-code to address this.
Omnifarious already hinted at one approach - use extensions inside a wrapper function. The slightly more robust method is to use an extern "C" wrapper function, in its own Translation Unit. Compile that whole Translation Unit as C11, without extensions.
This is generally more robust. Mixing code at source level requires advanced compiler support, whereas linking C and C++ is fairly straightforward.

C++ Force preprocessor to evaluate a number

I am writing a C++ program and I have predefined objects Serial1, Serial2, Serial3, etc. I need to make a function to operate on only one of them depending on a numeric input known at compile time. I use the concatenation macro #define SER(x) Serial##x but in my main if use SER(port).read() and port is an int equal to 1, expression expands to Serialport.read() instead of Serial1.read(). However, SER(1).read() gives the required result. How can I force the preprocessor to evaluate variable port and use its value in the expansion?
BTW, I don't know the class name of Serial1, Serial2, etc so I cannot design a workaround using pointers or references
EDIT: After seeing some answers, I need to add some clarification. I need to be able to use this function with all Serial1, Serial2, etc. by calling it multiple times in a SINGLE RUN of my code. Sorry for not making that clear before!
You need to use two levels of macros to accomplish what you are trying.
#define SER2(x) Serial##x
#define SER(x) SER2(x)
Here's a test program that demonstrates the concept.
#include <iostream>
#include <string>
struct Port
{
Port(std::string name) : name_(name) {}
void write()
{
std::cout << name_ << std::endl;
}
std::string name_;
};
Port Serial1("PORT1");
Port Serial2("PORT2");
#define SER2(x) Serial##x
#define SER(x) SER2(x)
int main()
{
SER(port).write();
}
Command to build:
g++ -std=c++11 -Wall socc.cc -o socc -Dport=1
Output:
PORT1
Command to build:
g++ -std=c++11 -Wall socc.cc -o socc -Dport=2
Output:
PORT2
Update
With the updated question, the only sensible approach is to use an array of objects and use the appropriate element of the array based on the run time data.
The fact that you don't know the type doesn't really matter: decltype(Serial1) will give that. Do you know whether they all have the same type? Because if they don't, no single C++ function can return them directly. And if they don't even have a common base class, it's even harder.
The template mechanism is more powerful than the preprocessor, so it makes sense to draft that:
template<int N> struct Serial { };
template<> struct Serial<1> { static decltype(Serial1)* const ptr = &Serial1 };
template<> struct Serial<2> { static decltype(Serial2)* const ptr = &Serial3 };
template<> struct Serial<3> { static decltype(Serial3)* const ptr = &Serial3 };
// You can now use Serial<8/2-2>.ptr->
Of course, writing out the template specializations is boring. So let's get Boost.PP :
#define BOOST_PP_LOCAL_MACRO (1, 7) // Assuming you have ports 1 to 7
#define BOOST_PP_LOCAL_MACRO(n) \
template<> struct Serial<n> { \
static decltype(BOOST_PP_CAT(Serial,n))* const ptr = &Serial##n; \
};
#include BOOST_PP_LOCAL_ITERATE()
Yes, that last line is a #include without quotes. And no, I'm not sure if this is an improvement ;)

Can I reliably turn a string literal into a symbol name using templates (or fancy macros)?

A bit of background: I want to write a tool that compiles a bunch of named things into C++ code. The list changes and I don't want to rebuild the world when that happens. Despite that, I want to address the compiled code by (literal) name.
As an example of something that's not quite right, I could have put this in a header:
template<int name> void func();
Then my tool can generate code like:
template<> void func<1>() { ... }
template<> void func<2>() { ... }
template<> void func<3>() { ... }
Now I can call these by "name" anywhere without pre-declaring each one.
I want to do this, but with something more descriptive than integers. Ideally I want text of some form. What I need is something like:
#define FUNC_WITH_NAME(name) func_named_ ## name
That doesn't quite work, though: it needs a declaration of func_named_whatever.
The next try is no good either (and it's GCC-specific):
#define FUNC_WITH_NAME(name) ({extern void func_named_ ## name; func_named_ ## name;})
It fails because, if it's used inside a namespace, then it ends up looking for func_named_whatever in that namespace.
The best I've come up with is this:
template<char... tagchars> int tagged();
namespace NS {
int caller()
{
return tagged<'n', 'a', 'm', 'e'>();
}
}
This works, but it's ugly (and it's not obvious how to turn a string literal into a parameter pack without jumping through nasty hoops). Also, if the symbol doesn't resolve, then the error message from g++ is terrible:
In function `NS::caller()':
named_symbol.cpp:(.text+0x5): undefined reference to `int tagged<(char)110, (char)97, (char)109, (char)101>()'
collect2: error: ld returned 1 exit status
The only thing that I've come up with is a gcc extension:
extern void func_named_whatever __asm__("func_named_whatever");
But this is no good as a template argument (it only affects calls to that function; it does not affect use of magic asm-ified symbols when they're template arguments), and it defeats any link-time type checking because it turns off mangling.
Now I can call these by "name" anywhere without pre-declaring each one.
To call any function at compile time, you need to forward-declare it.
Because you want to call them at compile time, there's no need to use string literals. And you can only do this using preprocessor, not templates, because you cannot specify identifier names for templates (in C++03, at least).
Example:
#include <iostream>
#define CALL_FUNC(func, args) name_ ##func args;
void name_func1(){
std::cout << "func1" << std::endl;
}
void name_func2(int a){
std::cout << "func2:" << a << std::endl;
}
int main(int argc, char** argv){
CALL_FUNC(func1, ());
CALL_FUNC(func2, (46));
return 0;
}
You can forward-declare function within function body:
#include <iostream>
int main(int argc, char** argv){
void name_func(int);
name_func(42);
return 0;
}
void name_func(int arg){
std::cout << "func1:" << arg << std::endl;
}
So, technically, you don't even need to use preprocessor for that.
You cannot avoid forward-declaration, unless all functions arguments are known as well as their types, in which case you can hide forward-declaration with macros.
#include <iostream>
#define FUNC_NAME(func) name_ ##func
#define CALL_VOID_FUNC(func) { void FUNC_NAME(func)(); FUNC_NAME(func)(); }
int main(int argc, char** argv){
CALL_VOID_FUNC(func1);//not forward declared
return 0;
}
void name_func1(){
std::cout << "func1" << std::endl;
}
Or if you want to specify function argument types every time you call functions and know number of arguments:
#include <iostream>
#define FUNC_NAME(func) name_ ##func
#define CALL_FUNC_1ARG(func, type1, arg1) { void FUNC_NAME(func)(type1); FUNC_NAME(func)(arg1); }
int main(int argc, char** argv){
CALL_FUNC_1ARG(func1, int, 42);
return 0;
}
void name_func1(int arg){
std::cout << "func1:" << arg << std::endl;
}
Or if your function can take variable number of arguments. (parsing varargs is fun):
#include <iostream>
#define FUNC_NAME(func) name_ ##func
#define CALL_FUNC_VARIADIC(func, args) { void FUNC_NAME(func)(...); FUNC_NAME(func)args; }
int main(int argc, char** argv){
CALL_FUNC_VARIADIC(func1, (42, 43, 44));
return 0;
}
void name_func1(...){
//std::cout << "func1:" << arg << std::endl;
}
If you want to use STRINGS (as in "func1"), then you are trying to locate function at run time, not at compile time, even if you don't really think so. That's because "funcname" isn't that different from (std::string(std::string("func") + std::string("name")).c_str()) - it is pointer to memory region with character. Some compiler might provide extensions to "unstringize" string, but I'm not aware of such extensions.
In this case your only option is to write either preprocessor or code-generator, that'll scan some kind of text template (that lists functions) every time you build the project, and converts it into .h/.cpp files that are then compiled into your project. Those .h/.cpp files shoudl build function table (name to function pointer map) that is then used "behind the scenes" in your project. See Qt MOC for a working example. That'll require recompilation every time you add new function to template.
If you do not want recompilation for every new function prototype (although you can't add call to a new function without recompiling project, obviously), then your only choice is to embed scripting language into your application. This way you'll be able to add functions without recompiling. At we momen, you can embed lua, python, lisp(via ecl) and other languages. There's also working C++ interpreter, although I doubt it is embeddable.
If you do not want to use any options I listed, then (AFAIK) you cannot do that at all. Drop some requirement ("no recompilation", "no forward declaration", "call using string literal") and try again.
Can I reliably turn a string literal into a symbol name using the C macro language?
No. You can turn string literal into identifier to be processed by compiler (using stringize), but if compiler doesn't know this identifier at this point of compilation, your code won't compile. So, if you're going to call functions this way using their names, then you'll have to insure that they all were forward-declared before. And you won't be able to locate them at runtime.
C++ doesn't store names for functions and variables in compiled code. So you can't find compiled function by its name. This is because C++ linker is free to eliminate unused functions completely, inline them or create multiple copies.
What you CAN do:
Create a table of functions that you want to address by name (that maps function name to function pointer), then use this table to locate functions. You'll have to manually register every function you want to be able to find in this table. Something like this:
typedef std::string FunctionName;
typedef void(*Function)(int arg);
typedef std::map<FunctionName, Function> FunctionMap;
FunctionMap globalFunctionMap;
void callFunction(const std::string &name, int arg){
FunctionMap::iterator found = globalFunctionMap.find(name);
if (found == globalFunctionMap.end()){
//could not find function
return;
}
(*found->second)(arg);
}
Use dynamic/shared libraries. Put functions you want to be able to address into shared library (extern "C" __declspec(dllexport) or __declspec(dllexport)), mark them for export then use operating system functions to locate function within library (dlsym on linux, GetProcAddress of windows). Afaik, you might be able export functions from exe as well, so you might be able to use this approach without additional dlls.
Embed scripting language into your application. Basically, in most scripting languages you can locate and call function by its name. That'll be function declared within scripting language, obviously, not a C++ function.
Write code preprocessor that'll scan your project for "named" functions and build table of those function (method #1) somewhere automatically. Can be very difficult, because C++ is not that easy to parse.
The ideal solution would be N3413, but that's a long way off.
With thanks to 0x499602d2 and Using strings in C++ template metaprograms, here's a so-so answer:
template<char... str>
struct tag
{
template<char first>
struct prepend
{
typedef tag<first, str...> type;
};
};
template<typename Tag>
void func();
#define PREPARE_STR_TAGGER(str) \
template<int charsleft> \
struct tagger_for_##str \
{ \
typedef typename \
tagger_for_##str<charsleft-1>::type:: \
template prepend<(#str)[sizeof(#str)-1-charsleft]>::type type; \
}; \
template<> \
struct tagger_for_##str<0> \
{ \
typedef tag<> type; \
};
#define STRING_TO_TAG(str) tagger_for_##str<sizeof(#str)-1>::type
namespace SHOULD_NOT_MATTER {
PREPARE_STR_TAGGER(some_string);
void test()
{
func<STRING_TO_TAG(some_string)>();
}
}
Downsides:
It's awkward to use: you need to use PREPARE_STR_TAGGER at namespace (or maybe class) scope.
It's probably unfriendly to compile time.
The linker errors it generates are awful.
Some kind of decent hash function based on constexpr would work, but it would result in even more awful error messages.
Improvements are welcome.

Unused parameter in c++11

In c++03 and earlier to disable compiler warning about unused parameter I usually use such code:
#define UNUSED(expr) do { (void)(expr); } while (0)
For example
int main(int argc, char *argv[])
{
UNUSED(argc);
UNUSED(argv);
return 0;
}
But macros are not best practice for c++, so.
Does any better solution appear with c++11 standard? I mean can I get rid of macros?
Thanks for all!
You can just omit the parameter names:
int main(int, char *[])
{
return 0;
}
And in the case of main, you can even omit the parameters altogether:
int main()
{
// no return implies return 0;
}
See "§ 3.6 Start and Termination" in the C++11 Standard.
There is the <tuple> in C++11, which includes the ready to use std::ignore object, that's allow us to write (very likely without imposing runtime overheads):
void f(int x)
{
std::ignore = x;
}
I have used a function with an empty body for that purpose:
template <typename T>
void ignore(T &&)
{ }
void f(int a, int b)
{
ignore(a);
ignore(b);
return;
}
I expect any serious compiler to optimize the function call away and it silences warnings for me.
To "disable" this warning, the best is to avoid writing the argument, just write the type.
void function( int, int )
{
}
or if you prefer, comment it out:
void function( int /*a*/, int /*b*/ )
{
}
You can mix named and unnamed arguments:
void function( int a, int /*b*/ )
{
}
With C++17 you have [[maybe_unused]] attribute specifier, like:
void function( [[maybe_unused]] int a, [[maybe_unused]] int b )
{
}
Nothing equivalent, no.
So you're stuck with the same old options. Are you happy to omit the names in the parameter list entirely?
int main(int, char**)
In the specific case of main, of course, you could simply omit the parameters themselves:
int main()
There are also the typical implementation-specific tricks, such as GCC's __attribute__((unused)).
What do you have against the old and standard way?
void f(int a, int b)
{
(void)a;
(void)b;
return;
}
Macros may not be ideal, but they do a good job for this particular purpose. I'd say stick to using the macro.
The Boost header <boost/core/ignore_unused.hpp> (Boost >= 1.56) defines, for this purpose, the function template boost::ignore_unused().
int fun(int foo, int bar)
{
boost::ignore_unused(bar);
#ifdef ENABLE_DEBUG_OUTPUT
if (foo < bar)
std::cerr << "warning! foo < bar";
#endif
return foo + 2;
}
PS C++17 has the [[maybe_unused]] attribute to suppresses warnings on unused entities.
There's nothing new available.
What works best for me is to comment out the parameter name in the implementation. That way, you get rid of the warning, but still retain some notion of what the parameter is (since the name is available).
Your macro (and every other cast-to-void approach) has the downside that you can actually use the parameter after using the macro. This can make code harder to maintain.
I really like using macros for this, because it allows you better control when you have different debug builds (e.g. if you want to build with asserts enabled):
#if defined(ENABLE_ASSERTS)
#define MY_ASSERT(x) assert(x)
#else
#define MY_ASSERT(x)
#end
#define MY_UNUSED(x)
#if defined(ENABLE_ASSERTS)
#define MY_USED_FOR_ASSERTS(x) x
#else
#define MY_USED_FOR_ASSERTS(x) MY_UNUSED(x)
#end
and then use it like:
int myFunc(int myInt, float MY_USED_FOR_ASSERTS(myFloat), char MY_UNUSED(myChar))
{
MY_ASSERT(myChar < 12.0f);
return myInt;
}
I have my own implementation for time critical segments of code.
I've been researching a while a time critical code for slow down and have found this implementation consumes about 2% from the time critical code i have being optimized:
#define UTILITY_UNUSED(exp) (void)(exp)
#define UTILITY_UNUSED2(e0, e1) UTILITY_UNUSED(e0); UTILITY_UNUSED(e1)
#define ASSERT_EQ(v1, v2) { UTILITY_UNUSED2(v1, v2); } (void)0
The time critical code has used the ASSERT* definitions for debug purposes, but in release it clearly has cutted out, but... Seems this one produces a bit faster code in Visual Studio 2015 Update 3:
#define UTILITY_UNUSED(exp) (void)(false ? (false ? ((void)(exp)) : (void)0) : (void)0)
#define UTILITY_UNUSED2(e0, e1) (void)(false ? (false ? ((void)(e0), (void)(e1)) : (void)0) : (void)0)
The reason is in double false ? expression. It somehow produces a bit faster code in release with maximal optimization.
I don't know why this is faster (seems a bug in compiler optimization), but it at least a better solution for that case of code.
Note:
Most important thing here is that a time critical code slow downs without above assertions or unused macroses in release. In another words the double false ? expression surprisingly helps to optimize a code.
windows.h defines UNREFERENCED_PARAMETER:
#define UNREFERENCED_PARAMETER(P) {(P) = (P);}
So you could do it like this:
#include <windows.h>
#include <stdio.h>
int main(int argc, char **argv) {
UNREFERENCED_PARAMETER(argc);
puts(argv[1]);
return 0;
}
Or outside of Windows:
#include <stdio.h>
#define UNREFERENCED_PARAMETER(P) {(P) = (P);}
int main(int argc, char **argv) {
UNREFERENCED_PARAMETER(argc);
puts(argv[1]);
return 0;
}

How can I implement assert macro as a method?

I want implement assert macro as a method in C++ like .NET Framewrk.
For example in C# we can invoke assert method like this:
Debug.Assert(index > -1);
and I want implement assert something like this:
#include <assert.h>
class debug
{
public:
static void my_asset(<condition>) // like assert macro
{
// ?
}
};
When using this class:
debug::my_asset(index > -1); // Actually should be called assert(index > -1);
Thanks
Edit:
I want when invoking debug::my_asset(index > -1);, It shows correct file name and line number, and it works like C++ asset macro.
There are several features of assert assert (in <assert.h> or <cassert>) that are of interest:
that when you're compiling a release build, the assert tests aren't evaluated at all.
the error message printed when an assertion fails can tell you the file and line number where your assertion failed
it can also tell you the exact code that failed.
You can't do these in C++ without using a macro.
The only way to get the line number, file, and text version is via macro. However:
#include <assert.h>
class debug
{
public:
static void my_assert(bool passed, const char* assert, const char* file, long line)
{
if (passed == false)
std::cout<<"failed assert "<<assert<<" in "<<file<<" at "<<line<<".\n";
}
#ifdef NDEBUG
#define myassert(x) my_assert(true, "", "", 0)
#else
#define myassert(x) my_assert(x, #x , __FILE__, __LINE__ )
#endif
};
int main() {
debug::myassert(sizeof(int)==4);
return 0,
}
This code works in an oddball way. The first x is the assert expression itself, evaluating to true or false, to tell my_assert what to do. The #x is a magic preprocessor command that makes a char* version of x, so we can display it. __FILE__ is replaced with the filename, and __LINE__ is replaced with the line number. (Since it's a macro, it has the same line number as the calling function).
When you type debug::myassert(sizeof(int)==4);, the preprocessor says "I know what myassert(whatever) is!" and replaces it. So it replaces it all with: debug::my_assert(sizeof(int)==4, "sizeof(int)==4", "main.cpp", 27);, which is a valid line of code. So if sizeof(int) is 8 for instance (it is on some machines), the first parameter is false, and the line is displayed "failed assert sizeof(int)==4 in main.cpp at 27."
static void my_asset(bool cond) // like assert macro
{
::assert(cond);
}
Doesn't work?
You could
void debug::my_assert(bool cond) {
ASSERT(cond);
}
This would work in that it would cause an exception when the assertion failed.
It's a little less helpful than the macro because my_assert can't see what the condition was that failed -- you'll get an assertion failure but no useful explanation (though you'll get an accurate stack trace in a debugger).
Also see Ken's reasons why a macro is more helpful.