Search code examples
c++staticconstantsc++buildervcl

Compiler error with 'static const std::wstring DELETE;'


I started a new VCL application under C++Builder, and I observe something bizarre.

When I declare a const member named DELETE as std::string, I get an error.

Here is the .h file:

#pragma once
#ifndef Communication_ButtonTagH
#define Communication_ButtonTagH    
#include <string>
namespace OverB::Communication
{
    class ButtonTag
    {
    public:
       static const  std::wstring  DELETE;
    };
}
#endif

And here is the .cpp file:

#include "Communication_ButtonTag.h"
namespace OverB::Communication
{
     const  std::wstring   ButtonTag::DELETE  = L"DELETE";
}

Changing only the name of the const, the application builds correctly.

I am using C++Builder 11.1 Alexandria, and Windows 11.

Here is the list of errors:

[C++ Error] Communication_ButtonTag.h(13, 32):  expected member name or ';' after declaration specifiers
[C++ Error] Communication_ButtonTag.h(13, 32):  expected ')'
[C++ Error] Communication_ButtonTag.h(13, 32):  to match this '('
[C++ Error] Communication_ButtonTag.cpp(5, 35):  expected unqualified-id

Can anyone explain what is happening exactly?


Solution

  • The VCL is built on top of the Win32 API, which has a DELETE preprocessor macro defined in winnt.h:

    #define DELETE                           (0x00010000L)
    

    The preprocessor is run first, and it performs text replacements of defined macros before the compiler is run. Thus, after the preprocessor has processed your code and made its replacements, the compiler will see the following invalid code, which is why it errors:

    #pragma once
    #ifndef Communication_ButtonTagH
    #define Communication_ButtonTagH    
    #include <string>
    namespace OverB::Communication
    {
        class ButtonTag
        {
        public:
           static const  std::wstring  (0x00010000L);
        };
    }
    #endif
    
    #include "Communication_ButtonTag.h"
    namespace OverB::Communication
    {
         const  std::wstring   ButtonTag::(0x00010000L)  = L"DELETE";
    }
    

    In short, don't declare your own variables and identifiers that happen to match the names of Win32 API macros. The Win32 API is primarily a C library, not a C++ library. It doesn't use properly typed constants, or respect namespaces, etc. Common C++ best practices go out the window when dealing with the Win32 SDK.