Search code examples
c++visual-c++language-lawyerdoxygenforward-declaration

Is it legal to cast a forward-declared type to void?


Below is a C++ header file that compiles without error under g++ and clang, but under MSVC2015, it errors out on the (void) copyFrom line, with the error C2027: use of undefined type 'blah::SomeOtherClass'.

My question is: is this code legal according to the C++ standard? Or if the code is not correct (i.e. because casting a parameter to (void) legitimately requires more than just a forward-declaration), then what would be a good way to retain my DOxygen documentation for the copyFrom argument without introducing unwanted parameter copyFrom was never referenced warnings into my compiler-output? (Note that the full definition of SomeOtherClass isn't available at this point, since SomeOtherClass depends on DummyImplementation)

#ifndef blah_h
#define blah_h

namespace blah {

class SomeOtherClass;

/** Example of the problem at hand */
class DummyImplementation
{
public:
   /** Dummy implemention of CopyFrom().
    *  @param copyFrom This parameter is ignored.
    *  @returns zero.
    */
   int CopyFrom(const SomeOtherClass & copyFrom)
   {
      (void) copyFrom;  // error C2027: use of undefined type 'blah::SomeOtherClass'
      return 0;
   }
};

} // end namespace blah

#endif

Update: Per Francois' request, here are the build my program uses when building with MSVC 19.0.24210.0 (not that the answer to a question about the requirements of the C++ standard should depend on the behavior of a particular version of MSVC):

cl -c -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline /nologo /MP 
/arch:SSE2 /Zi -O2 -MD -Zc:strictStrings -GR -W3 -w34100 -w34189 -w44996 
-EHsc -D_WIN32_WINNT=0x0601 -DNDEBUG -D__WIN32__ -D_USE_MATH_DEFINES 
-DQT_NO_CAST_ASCII -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB
[... various -I flags omitted ...]

Solution

  • For the full story, please refer to this answer.

    According to cppref, for (type-name) expression (emphasis mine)

    If type-name is void, then expression is evaluated for its side-effects and its returned value is discarded, same as when expression is used on its own, as an expression statement.

    That is, (void)copyFrom is equivalent to copyFrom which has no effect, and should not require a complete type in C++.

    By the way, your code compiles fine with MSVC 2017 (live).

    To suppress the compiler warning, you may consider:

    std::addressof(copyFrom)