20

The following code generates warning C4127 (conditional expression is constant) in Visual Studio 2010 (where alias_wchar_t is an alias for wchar_t):

if (sizeof(alias_wchar_t) == sizeof(wchar_t)) // warning occurs here
{
    // do stuff
}
else
{
    // do other stuff
}

What's the most elegant way to resolve this, short of suppressing the warning?

The best solution I've come up with is to stuff the conditional into a static bool, and use that as the condition. There's a goodly amount of code above and below the if-else, so I wrap the whole thing in braces to limit the scope of the variable as much as possible:

// <snip>

{
    static bool isSameSize = (sizeof(alias_wchar_t) == sizeof(wchar_t));
    if (isSameSize)
    {
        // do stuff
    }
    else
    {
        // do other stuff
    }
}

// <snip>

This feels pretty gross though. This seems like it should be resolvable at compile-time rather than runtime, but the preprocessor doesn't know about sizeof. Is there a cleaner, more elegant way to resolve this?

Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
Christopher Berman
  • 719
  • 1
  • 5
  • 21
  • 3
    note: C++17 is considering something like `if constexpr` which would solve this problem – M.M Mar 22 '16 at 05:12

6 Answers6

8

What's the most elegant way to resolve this, short of suppressing the warning?

The condition is known at compile time, so you can make the check at compile time, too. Don't use an if, just let the compiler insert a call to the right function. Here is a complete example:

#include <iostream>

typedef short alias_wchar_t; // for testing

template<bool Condition>
struct DoStuff
{
};

template<>
struct DoStuff<true>
{
    static void doStuff()
    {
        std::cout << "sizeof(alias_wchar_t) == sizeof(wchar_t)\n"; 
    }
};

template<>
struct DoStuff<false>
{
    static void doStuff()
    {
        std::cout << "sizeof(alias_wchar_t) != sizeof(wchar_t)\n"; 
    }
};

void doStuff()
{
    DoStuff<sizeof(alias_wchar_t) == sizeof(wchar_t)>::doStuff();
}

int main()
{
    doStuff();
}

Whether that's really more elegant than your original code (with just that particular compiler warning turned off for this compilation unit) is opinion-based, I'd say.

In any case, this compiles with no warnings at /W4 with VC 2013.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
  • 3
    don't you think you've just doubled the amount of code to mantain ;) – Alexander Enaldiev Dec 15 '16 at 09:47
  • 1
    @AlexanderEnaldiev: Code length is not the only factor in determining how easily something can be maintained. As I said here more than two years ago, whether it's more elegant or not depends on the actual context of the code. – Christian Hackl Dec 15 '16 at 12:31
  • Can't agree with you. It could be pointless. Let's say template struct Foo { bool Check() { bool retval = checkImpl(); if (Strict) retval = retval && checkStrict(); return retval; } }; What for I have C4127 here? Don't you think, I'm pretty sure that the constant depends on the template arg? Or what's the point of C4127. What does it show? Can't figure out still. Regardless of years passed ;) – Alexander Enaldiev Dec 16 '16 at 20:47
  • @AlexanderEnaldiev: I don't get C4217 for that. Visual C++ 2015, `/W4` (not even with `/Wall`). That being said, it could be made more elegant and I wouldn't mind a warning for it. You basically have two different classes `Foo` and `Foo`, one testing `true == true` and the other one `true == false`. Template specialisation would be conceptually cleaner. – Christian Hackl Dec 17 '16 at 09:59
  • It turns you're right and I was mistaken, - they've removed it since ~VS2013. The time goes by. (could be easily reproduced by using VS2010, but nowadays one could consider vs2010 as a legacy compiler (say, regarding to the C++0x, C++0y features support)). – Alexander Enaldiev Dec 20 '16 at 16:31
8

In C++17, the solution is to use if constexpr:

if constexpr (sizeof(alias_wchar_t) == sizeof(wchar_t)) // warning occurs here
{
    // do stuff
}
else
{
    // do other stuff
}

Reference: Visual C++ Blog

Arnaud
  • 3,765
  • 3
  • 39
  • 69
7

It looks like you know what is going on, and you are fine with this.

Compiler pragmas are meant for cases like that:

__pragma(warning(push))
__pragma(warning(disable:4127))
if (sizeof(alias_wchar_t) == sizeof(wchar_t)) {
__pragma(warning(pop))
}

Essentially, you are telling the compiler (and even more importantly, to human readers of your code) that you have reviewed the warning, and that you know what you are doing.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 5
    Personally I think Christopher Berman's original solution is better. Pragmas are compiler specific and excessively verbose. – Benilda Key Aug 29 '14 at 18:32
  • 1
    If you are in a situation where you need to use such kind of constant conditions, there's the much shorter "suppression" pragma: `__pragma(warning(suppress: 4127)) if (sizeof(alias_wchar_t) == sizeof(wchar_t)) ...;` – klaus triendl May 15 '22 at 11:49
4

An other way to disable the warning is to create a dummy identity function and use it on one of the constants.

// Define this somewhere
template<typename T> const T& identity(const T& t) { return t; }

...

// NB: 'identity' used only to remove "warning C4127"
if (identity(sizeof(alias_wchar_t)) == sizeof(wchar_t))
{
    // do stuff
}
else
{
    // do other stuff
}

This is not perfect but seems more lightweight than other solutions and reusable for different type of constants.

Rexxar
  • 1,886
  • 1
  • 14
  • 19
3

This is what I have come up with. It does not cause any warnings in Microsoft Visual Studio 2013 and it does not require that you use Visual C++ specific Pragmas.

First define the following template class.

template <bool b>
struct condition
{
    static bool test()
    {
        return true;
    }
};
template <>
struct condition<false>
{
    static bool test()
    {
        return false;
    }
};

Then use it as follows.

if (condition<sizeof(alias_wchar_t) == sizeof(wchar_t)>::test())

I got the idea from the C++14 std::conditional described at http://en.cppreference.com/w/cpp/types/conditional.

Benilda Key
  • 2,836
  • 1
  • 22
  • 34
2

If it's just a constant expression then use:

typedef wchar_t alias_wchar_t;
bool constExpression = sizeof(alias_wchar_t) == sizeof(wchar_t);
if (constExpression) // potential warning
{
    // do stuff
}
else
{
    // do other stuff
}

It appears the c4127 is generated by the mere action of evaluating a constant expression in the control statement.

Laurie Stearn
  • 959
  • 1
  • 13
  • 34
  • I used a variant of this with success: constexpr bool constExpression = sizeof(alias_wchar_t) == sizeof(wchar_t); if (constExpression) {} – Rogério Ramos Jun 20 '17 at 06:00
  • This did not work for me, using the VS2012 compiler. Still got the same warning on the "if" statement. – T.E.D. Apr 26 '18 at 15:56