known(T, expr) — Cheap Compile-Time Type Assertion

known(T, expr) asserts at compile time that expr is of type T, then passes the value through unchanged. It is a zero-cost alternative to inline functions for type-checking inside macros.

int* ptr = get_ptr();
void* p = known(int*, ptr);    // OK: ptr is int*

char* wrong = get_char();
void* p = known(int*, wrong);  // ERROR (C++ build): type mismatch

In C, known(T, expr) is (expr) — a no-op. The C++ build uses a static_assert that fires if the types don’t match.

Why Not an Inline Function?

Three reasons:

  1. Debug build cost. Inline functions are not inlined in debug builds. known() is zero cost even in -O0.
  2. Const propagation. A function must pick const T* or T*. known() passes through whatever constness the expression has (lenient) or errors on mismatch (rigid).
  3. Macro composability. Writing a macro that delegates to a function for type checking forces split definitions. known() stays inside the macro.

Lenient vs. Rigid

The lenient form of known_cast() is quite useful for writing polymorphic macros which are const-in => const-out and mutable-in => mutable-out. This tends to be more useful than wanting to enforce that only mutable pointers can be passed into a macro (the bulk of macros are reading operations, anyway). So lenient defaults the short name known_cast().

Variant Behavior
lenient_known(T, expr) Accepts const T when T is specified; passes const through
rigid_known(T, expr) Errors if expr has different const-ness than T
known(T, expr) Alias for lenient_known
const int* cp = get_const();
int* mp = get_mutable();

lenient_known(int*, cp);   // OK: accepts const int* when int* specified
rigid_known(int*, cp);     // ERROR: cp is const int*, not int*
rigid_known(int*, mp);     // OK: exact match

known_not and known_any

known_not(int*, expr)               // asserts expr is NOT int*
known_any((int*, char*, void*), expr)  // asserts expr is one of the listed types

lenient_exactly and rigid_exactly

These check that expr is exactly a specified type (no inheritance or implicit conversions). lenient_exactly(T, expr) accepts const T as a match; rigid_exactly(T, expr) requires the exact type including mutability.

known_lvalue

known_lvalue(variable)   // compile error if variable is not an lvalue

Useful in “evil macros” that use their arguments more than once: ensures the caller passes a simple variable, not an expression with side effects.


Compile-Time Tests

Basic type assertion

#ifdef __cplusplus
  #define NEEDFUL_CPP_ENHANCED  1
#endif
#define NEEDFUL_KNOWN_SHORTHANDS  1
#include "needful.h"

int main() {
    int value = 10;
    int* ptr = &value;

    void* p = lenient_known(int*, ptr);  // OK: ptr is int*
    NEEDFUL_UNUSED(p);

    const int* cp = ptr;
    const void* q = lenient_known(int*, cp);   // OK: passes through const int*
    NEEDFUL_UNUSED(q);

    return 0;
}

rigid_known rejects a const pointer where mutable is required

// MATCH-ERROR-TEXT: static assertion failed  <- GCC/Clang
// MATCH-ERROR-TEXT: static_assert            <- MSVC

#ifdef __cplusplus
  #define NEEDFUL_CPP_ENHANCED  1
#endif
#define NEEDFUL_KNOWN_SHORTHANDS  1
#include "needful.h"

int main() {
    const int* cp = nullptr;
    int* p = rigid_known(int*, cp);  // ERROR: const int* != int*
    NEEDFUL_UNUSED(p);
    return 0;
}