Implementation of a compile-time mechanism that checks the uniqueness of a string

The easiest way to identify my problem is that I am trying to implement a mechanism that would check if the same string (or a pair (number, string)) has already been used. I would like this mechanism to be implemented intelligently using the C preprocessor. I would also like this mechanism to allow me to compile errors when there are conflicts or errors during execution in debug mode (by checking statements). We do not want the developer to make a mistake when adding a message, since each message must be unique. I know that this can be done by computing a hash or, for example, crc / md5but this mechanism will be vulnerable to conflict, which I must avoid. It is imperative that each message can only be used once.

An example of the behavior 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 behavior (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 to do this would be to use the #define and #undef directives wisely . In general, the preprocessor should be used in a smart way (I'm not sure if this is possible), maybe this can be achieved using the appropriate combinations of macros? Any C preprocessor hacker that can help me solve this problem?

// EDIT: I need these messages to be unique throughout the world, and not just inside one block of code (for example, the if-statement function).

//EDIT2: , 100 , (, , , script , ), ( ) . , ( , , , ).

+4
5

:

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");

g++:

g++ -std=c++11 unique.cpp 
unique.cpp: In instantiation ofconst 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

( 0) 'assert_equality' .

+4

, ++ ( , ). - (, GPP)

-: X-macro "header" (, , awk script, ). (, Makefile), script .

, , , GCC, GCC MELT (, , ).

Emacs, ( ) emacs ( #define -s C).

+2

, - :

addMessage(1, "Message1")
addMessage(2, "Message1")

:

addMessage(1, "Message") /* transforms into "Message_1" */
addMessage(2, "Message_1") /* transforms into "Message_1_2" */

C , , .

, :

#define addMessage(N, MSG) const char *_error_message_##N (void) { return MSG; }

:

#define addMessage(N, MSG) const char *_error_message_##N (void) { return MSG "_" #N; }

_error_message_NUMBER . , .

+2

, - ++ 11, . , , , , .

#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 
    };

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;                   \
        ^
+2

, , , , , ... p >

:

#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;

#include d , , #define ERROR. , , .

, Boost.Preprocessor( ). , , , #if HAVE_BOOST.

, , (, - script), , .

+1
source

All Articles