2

Is it possible to define a macro that would accept expression like: object.method()? I would like to make a macro that changes that expression into... nothing (kind of deletes it). With just function() I would do: #define function (without any value) but is it possible to create a macro with dot in it?

Edit: Regarding MooingDuck's comment:

object.Method("text", "other");

Definition:

void Class::Method(std::string arg1, std::string arg2)
{
#if 0
    if (condition)
    {
        Method2(arg1, arg2);
    }
#endif
}

Disassembly:

    object.Method("text", "other");
00394396  mov         edi,5  
0039439B  mov         eax,offset string "other" (396348h)  
003943A0  lea         esi,[ebp-4Ch]  
003943A3  mov         dword ptr [ebp-38h],0Fh  
003943AA  mov         dword ptr [ebp-3Ch],ebx  
003943AD  mov         byte ptr [ebp-4Ch],bl  
003943B0  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign (393360h)  
003943B5  mov         dword ptr [ebp-4],1  
003943BC  mov         edi,4  
003943C1  mov         eax,offset string "text" (396350h)  
003943C6  lea         esi,[ebp-30h]  
003943C9  mov         dword ptr [ebp-1Ch],0Fh  
003943D0  mov         dword ptr [ebp-20h],ebx  
003943D3  mov         byte ptr [ebp-30h],bl  
003943D6  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign (393360h)  
003943DB  mov         esi,10h  
003943E0  mov         dword ptr [ebp-4],0FFFFFFFFh  
003943E7  cmp         dword ptr [ebp-1Ch],esi  
003943EA  jb          main+0B9h (3943F9h)  
003943EC  mov         eax,dword ptr [ebp-30h]  
003943EF  push        eax  
003943F0  call        dword ptr [__imp_operator delete (3960ECh)]  
003943F6  add         esp,4  
003943F9  mov         edi,0Fh  
003943FE  mov         dword ptr [ebp-1Ch],edi  
00394401  mov         dword ptr [ebp-20h],ebx  
00394404  mov         byte ptr [ebp-30h],bl  
00394407  cmp         dword ptr [ebp-38h],esi  
0039440A  jb          main+0D9h (394419h)  
0039440C  mov         ecx,dword ptr [ebp-4Ch]  
0039440F  push        ecx  
00394410  call        dword ptr [__imp_operator delete (3960ECh)]  
00394416  add         esp,4  
NPS
  • 6,003
  • 11
  • 53
  • 90
  • For something like this you would use the `#ifdef`/`#endif` constructs. Using macros for this is almost certainly a bad idea (if it's even possible). What problem are you trying to solve, exactly? – In silico Apr 26 '13 at 00:40
  • 2
    A macro name must be an identifier; it cannot include a `.` character. – Keith Thompson Apr 26 '13 at 00:41
  • For *any* named method? Or for a specific set of named methods? – Drew Dormann Apr 26 '13 at 00:49
  • @Insilico How exactly would I use `#ifdef`/`#endif`? @DrewDormann For one specified method. – NPS Apr 26 '13 at 00:50
  • 4
    This sounds like an [XY Problem](http://meta.stackexchange.com/questions/66377). If you *did* have this macro, how/when would you be using it? – Drew Dormann Apr 26 '13 at 00:52
  • I assume In silico means you put #ifdef around the definition / implementation of the "offending" method. I would agree with his original question... why do you want to do this? – Foon Apr 26 '13 at 00:53
  • @NPS: Take a look here for an example: http://msdn.microsoft.com/en-us/library/ew2hz0yd.aspx (scroll down a bit). Basically, it allows you to "turn off" code fragments based on the presence of a `#define`. – In silico Apr 26 '13 at 00:58
  • @Insilico I want to turn some class's methods off in Release mode but keep them on in Debug. Kind of like `assert()` but with class's methods. – NPS Apr 26 '13 at 01:03
  • 2
    @NPS: Just conditionally compile the code within said method. If the method is empty, it will be inlined away to nothing. – K-ballo Apr 26 '13 at 01:12
  • @K-ballo I thought so too but checked the dissasembly and it wasn't (it still created/copied parameters and did other stuff). VS2010. – NPS Apr 26 '13 at 01:16
  • 1
    @NPS: Did you check in Release mode? In debug mode, inlining is disabled. – Mooing Duck Apr 26 '13 at 01:51
  • @MooingDuck Yes, I checked in Release mode. – NPS Apr 26 '13 at 09:16
  • @K-ballo: That doesn't sound right at all. In release mode, empty functions shouldn't have that. Are you certain that the code in the function was entirely conditionally compiled away? Is the function virtual? Does copying the parameters have side effects? – Mooing Duck Apr 26 '13 at 18:11
  • @MooingDuck: I believe you meant that for _NPS_, not me – K-ballo Apr 26 '13 at 18:46
  • @MooingDuck See the edit to my question for code samples and disassembly. – NPS Apr 26 '13 at 20:17
  • @NPS: Why does your function make copies of the strings? I'm not good with assembly, but that looks like it's constructing the two string parameters and then destroying them both. The function has indeed been entirely compiled away. Use `const std::string&` instead of just `std::string`, and see if that fixes the issue. – Mooing Duck Apr 26 '13 at 20:19
  • @MooingDuck Corrected it and the disassembly changed a little but the problem remains the same - the method body is gone but it does some work with the parameters. :P – NPS Apr 26 '13 at 21:32
  • Oh wait, you're right, because it's converting the string literals to `std::string` still. – Mooing Duck Apr 26 '13 at 21:46

2 Answers2

3

Your code is:

void Class::Method(const std::string& arg1, const std::string& arg2)
{
#if 0
    if (condition)
    {
        Method2(arg1, arg2);
    }
#endif
}

But the problem is that when you call this with string literals, it's still constructing the std::string objects because the process of constructing them might have side effects.

I think I would try this, which won't do conversions until inside of the function, and thus the compiler can elide the std::string constructions as well.

template<class arg1_t, class arg2_t>
void Class::Method(const arg1_t& arg1, const arg2_t& arg2)
{
#if 0
    if (condition)
    {
        Method2(arg1, arg2);
    }
#endif
}
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • That works, thanks. I had different solution but this one's better as it allows only my class's methods to be ignored. But it still relies on the compiler's ability to optimize (get rid of) the methods. But that's something I won't avoid. Or will I? – NPS Apr 26 '13 at 22:36
  • There's always `#define Method(X, Y) Method`, but I REALLY don't recommend that. – Mooing Duck Apr 27 '13 at 00:46
  • @NPS http://www.parashift.com/c++-faq/inline-vs-macros.html and http://stackoverflow.com/questions/14041453/why-preprocessor-macros-are-evil-and-what-is-the-real-alternative-c11 – Mooing Duck Apr 27 '13 at 15:23
  • Except for global scope of names, I don't really see why you wouldn't recommend that. – NPS Apr 27 '13 at 18:29
  • Actually your solution doesn't work for this method call: `object.Method("text", std::string("other"));` I wanted compiler to get rid of the call completely and here it wastes time on creating `std::string`. Just noticed. :P – NPS Apr 27 '13 at 19:16
  • The macro in my comment should work for that situation though – Mooing Duck Apr 28 '13 at 02:19
2

The name of the macro is an identifier. There is no way around.

Different compilers may allow different characters into identifier (like $), but none of them allow .. At the end of the day C-preprocessor was designed to be a "light preprocessor", not intended for fancy conversions like other, much more powerful preprocessors, that were existing in mid 80's.

Although you can do something like this (not really recommended):

struct DoNothing
{
    void method() { }
};

DoNothing g_inst;

#define object g_inst

Almost certainly the macro generated code will be completely removed by the optimizer. This approach is sensitive to all used names. Everything should be explicitly mentioned.

Kirill Kobelev
  • 10,252
  • 6
  • 30
  • 51