안내: 이 포스트는 기존 블로그와 호환성을 위해 https://blog.juhwijung.com/6로도 들어올 수 있습니다.

여기까지의 작업내용: https://github.com/hwi-middle/HimchanSoftwareRenderer/tree/f069823fcd73b59876f2b7fddf085b1d647bf826

Assertion 매크로

#pragma once

#ifdef NDEBUG

#define ASSERT(expression) ((void)0)

#else
#include <fstream>
#include <iostream>
#include <sstream>

#define ASSERT(expression) do {                                                 \
    if (!(expression)) {                                                        \
		std::ostringstream messageStream;                                       \
		messageStream << "Assertion failed: " << #expression << "\n";	        \
        messageStream << "at [" << __FILE__ << "] (" << __func__ << ")\n";      \
        messageStream << "line " << __LINE__ << "\n";                           \
		std::ofstream outfile("Error.log");                                     \
		std::cerr.rdbuf(outfile.rdbuf());                                       \
        std::cerr << messageStream.str();                                       \
        std::cout << messageStream.str();                                       \
        std::cout << "The log file has been saved as 'Error.log'";              \
        __debugbreak();                                                         \
    }                                                                           \
} while (0)

#endif

__debugbreak를 통해서 런타임 assertion을 구현했다. 다만 문제가 있었는데, constexpr 함수에서는 이 매크로를 사용할 수 없었다. 내가 만든 ASSERT 매크로는 런타임 assertion인데 constexpr 함수의 내부에서는 컴파일 타임에 값을 결정해야하기 때문이다.

C 표준의 assert 매크로는 constexpr 함수에서도 사용할 수 있어서 별 생각없이 나도 런타임 assertion 매크로를 구현했는데, 애초에 C 표준 assert 매크로도 C++ 11까지는 constexpr 함수에서 사용할 수 없었다가 C++ 14에 들어서 가능하게 바뀌었다고 한다. constexpr 함수의 규칙에 일종의 예외를 둔 것이다.

내가 만든 매크로는 이러한 예외가 될 수 없으므로 constexpr 함수에서 사용할 수 없다. 그렇다면 선택지는 간단하다. 그냥 얌전히 C 표준의 assert매크로를 쓰거나, constexpr에서만 내가 만든 ASSERT를 피해가거나, constexpr 함수를 쓰지말거나…

고르자면 그냥 C 표준의 assert 매크로를 쓰는게 나을 것 같다.

아쉽지만 공부한 셈 치고 넘어가도록 하자.