MareArts ANPR mobile app

12/16/2025

Shows difference between functions, concepts, and constexpr variables

 

.

// study.marearts.com: When to use () and when not to in C++
// Shows difference between functions, concepts, and constexpr variables

#include <iostream>
#include <concepts>

// ==========================================
// CASE 1: FUNCTION - NEEDS ()
// ==========================================

// Regular function
bool isPositiveFunction(int x) {
return x > 0;
}

// constexpr function
constexpr bool isPositiveConstexpr(int x) {
return x > 0;
}

// consteval function (C++20)
template <typename T>
consteval bool IsIntegerFunction() {
return std::is_integral_v<T>;
}

void example1() {
std::cout << "\n=== CASE 1: FUNCTIONS - MUST USE () === study.marearts.com" << std::endl;
// Functions NEED ()
if (isPositiveFunction(5)) { // ← () required
std::cout << "✓ 5 is positive (function call)" << std::endl;
}
if constexpr (IsIntegerFunction<int>()) { // ← () required
std::cout << "✓ int is integer (consteval function call)" << std::endl;
}
// ❌ This would be ERROR:
// if (isPositiveFunction) { } // ERROR: can't use function without calling it
}

// ==========================================
// CASE 2: CONCEPT - NO ()
// ==========================================

// Concept (C++20)
template <typename T>
concept IsInteger = std::is_integral_v<T>;

void example2() {
std::cout << "\n=== CASE 2: CONCEPTS - NO () === study.marearts.com" << std::endl;
// Concepts don't use ()
if constexpr (IsInteger<int>) { // ← NO () - it's a concept, not function
std::cout << "✓ int is integer (concept check)" << std::endl;
}
// ❌ This would be ERROR:
// if constexpr (IsInteger<int>()) { } // ERROR: concept is not a function
}

// ==========================================
// CASE 3: CONSTEXPR VARIABLE - NO ()
// ==========================================

// constexpr variable
template <typename T>
constexpr bool is_integer_variable = std::is_integral_v<T>;

void example3() {
std::cout << "\n=== CASE 3: CONSTEXPR VARIABLES - NO () === study.marearts.com" << std::endl;
// constexpr variables don't use ()
if constexpr (is_integer_variable<int>) { // ← NO () - it's a variable, not function
std::cout << "✓ int is integer (constexpr variable)" << std::endl;
}
// ❌ This would be ERROR:
// if constexpr (is_integer_variable<int>()) { } // ERROR: variable is not callable
}

// ==========================================
// COMPARISON IN SAME CONTEXT
// ==========================================

// All three doing the same thing, different ways:
template <typename T>
consteval bool IsPositiveFunction() { return sizeof(T) > 0; } // Function

template <typename T>
concept IsPositiveConcept = sizeof(T) > 0; // Concept

template <typename T>
constexpr bool is_positive_variable = sizeof(T) > 0; // Variable

void example4() {
std::cout << "\n=== COMPARISON: FUNCTION vs CONCEPT vs VARIABLE === study.marearts.com" << std::endl;
// Function needs ()
if constexpr (IsPositiveFunction<int>()) { // ← () YES
std::cout << "✓ Function: use ()" << std::endl;
}
// Concept doesn't use ()
if constexpr (IsPositiveConcept<int>) { // ← () NO
std::cout << "✓ Concept: no ()" << std::endl;
}
// Variable doesn't use ()
if constexpr (is_positive_variable<int>) { // ← () NO
std::cout << "✓ Variable: no ()" << std::endl;
}
}

// ==========================================
// DISPATCHER PATTERN EXAMPLE
// ==========================================

// Like CK Builder dispatcher!

// Old way: consteval functions (need ())
template <typename T>
consteval bool IsSpecialAlgorithmFunction() { return sizeof(T) > 4; }

// New way: concepts (no ())
template <typename T>
concept IsSpecialAlgorithmConcept = sizeof(T) > 4;

template <typename T>
void dispatch_old_way() {
if constexpr (IsSpecialAlgorithmFunction<T>()) { // ← () YES (function)
std::cout << "Old dispatcher: Special algorithm (function)" << std::endl;
}
else {
std::cout << "Old dispatcher: Normal algorithm" << std::endl;
}
}

template <typename T>
void dispatch_new_way() {
if constexpr (IsSpecialAlgorithmConcept<T>) { // ← () NO (concept)
std::cout << "New dispatcher: Special algorithm (concept)" << std::endl;
}
else {
std::cout << "New dispatcher: Normal algorithm" << std::endl;
}
}

void example5() {
std::cout << "\n=== DISPATCHER PATTERN (Like CK Builder) ===" << std::endl;
dispatch_old_way<long>(); // Old way with functions
dispatch_new_way<long>(); // New way with concepts
}

// ==========================================
// MAIN
// ==========================================

int main() {
std::cout << "=== When to Use () in C++ === study.marearts.com" << std::endl;
example1(); // Functions
example2(); // Concepts
example3(); // Variables
example4(); // Comparison
example5(); // Dispatcher pattern
std::cout << "\n=== SUMMARY ===" << std::endl;
std::cout << "FUNCTION: Use () → IsXXX<T>()" << std::endl;
std::cout << "CONCEPT: No () → IsXXX<T>" << std::endl;
std::cout << "VARIABLE: No () → is_xxx<T>" << std::endl;
return 0;
}

/*
TO COMPILE:
g++ -std=c++20 when_to_use_parentheses.cpp -o when_to_use_parentheses
./when_to_use_parentheses

OUTPUT:
Functions need ()
Concepts don't need ()
Variables don't need ()
*/


..

Compile-Time vs Runtime

1. Concept - Always Compile Time 

template <typename T>

concept IsInteger = std::is_integral_v<T>;


// Checked at COMPILE TIME:

if constexpr (IsInteger<int>) {  // ← Compiler checks this

    // This code exists in binary

}

else {

    // This code REMOVED from binary

}

Compiler decides which branch to include in the compiled program.

2. constexpr - Can Be Either

Compiler decides based on context!

3. consteval - MUST Be Compile Time ✅








12/15/2025

C++20, consteval and comma operator example code

 

.

// (study.marearts.com): Compile-time Validation Pattern with consteval + static_assert
// C++20 required for consteval

#include <iostream>

// ==========================================
// EXAMPLE 1: Simple consteval function
// ==========================================

// consteval = MUST run at compile time (C++20 feature)
consteval int add(int a, int b) {
return a + b;
}

void example1() {
// This is evaluated at COMPILE TIME!
constexpr int result = add(5, 3); // Compiler computes: 5 + 3 = 8
std::cout << "(study.marearts.com) Example 1 : 5 + 3 = " << result << std::endl;
}

// ==========================================
// EXAMPLE 2: Comma operator
// ==========================================

void printMessage() {
std::cout << "Message printed!" << std::endl;
// Returns nothing (void)
}

void example2() {
// Comma operator: (A, B) evaluates A, then returns B
int x = (printMessage(), 42);
// ↓ ↓
// Calls function Returns 42
std::cout << "(study.marearts.com) Example 2: x = " << x << std::endl; // x = 42
}

// ==========================================
// EXAMPLE 3: consteval with static_assert (VALIDATION!)
// ==========================================

// Validation function - checks if number is positive
template <int N>
consteval void ValidatePositive() {
static_assert(N > 0, "ERROR: Number must be positive!");
// If N <= 0, compilation FAILS here with error message
// If N > 0, function completes
}

// Example struct that validates its template parameter
template <int Number>
struct PositiveNumber {
// This line forces validation at compile time!
// If Number is negative, compilation fails
static constexpr auto kValidation = (ValidatePositive<Number>(), 0);
// ↓ ↓
// Run checks (compile time) Return 0
int value = Number;
void print() {
std::cout << "Positive number: " << value << std::endl;
}
};

void example3() {
std::cout << "\n(study.marearts.com) Example 3: Compile-time validation" << std::endl;
// ✅ This COMPILES (5 > 0)
PositiveNumber<5> good;
good.print();
// ❌ This would FAIL to compile (uncomment to see error!)
// PositiveNumber<-3> bad;
// Error: static assertion failed: ERROR: Number must be positive!
std::cout << "✓ Validation passed at compile time!" << std::endl;
}

// ==========================================
// EXAMPLE 4: Real-world pattern (like our code!)
// ==========================================

enum class OperationType {
PASS_THROUGH,
ADD_ONE,
MULTIPLY_TWO
};

// Configuration struct (like our ConvSignature)
template <OperationType Op>
struct Config {
static constexpr OperationType operation = Op;
};

// Validation: Only allow PASS_THROUGH
template <auto Cfg>
consteval void ValidateConfig() {
static_assert(Cfg.operation == OperationType::PASS_THROUGH,
"ERROR: Simple implementation only supports PASS_THROUGH!");
}

// Simple implementation (like our ReferenceForwardFactory)
template <auto CONFIG>
struct SimpleProcessor {
// Validate at compile time!
static constexpr auto kValidation = (ValidateConfig<CONFIG>(), 0);
void process(int x) {
std::cout << "Processing " << x << " (PassThrough only)" << std::endl;
}
};

void example4() {
std::cout << "\nExample 4: Real-world validation pattern" << std::endl;
// ✅ This COMPILES (uses PASS_THROUGH)
constexpr Config<OperationType::PASS_THROUGH> good_config;
SimpleProcessor<good_config> processor;
processor.process(42);
// ❌ This would FAIL to compile (uncomment to see error!)
// constexpr Config<OperationType::ADD_ONE> bad_config;
// SimpleProcessor<bad_config> bad_processor;
// Error: static assertion failed: Simple implementation only supports PASS_THROUGH!
std::cout << "✓ Config validation passed!" << std::endl;
}

// ==========================================
// MAIN
// ==========================================

int main() {
std::cout << "=== Compile-Time Validation Study ===" << std::endl;
example1(); // consteval basics
example2(); // comma operator
example3(); // consteval + static_assert
example4(); // real-world pattern
std::cout << "\n✓ All examples passed!" << std::endl;
return 0;
}

..

KEY CONCEPTS:

1. consteval (C++20):
- Function MUST execute at compile time
- Cannot be called at runtime

2. static_assert (C++11):
- Checks condition at compile time
- If false, compilation FAILS with error message

3. Comma operator:
- (A, B) executes A, then returns B
- Used to "call void function" in member initialization

4. The Pattern:
static constexpr auto kValidation = (ValidateFunction<>(), 0);
- Forces compile-time validation
- Returns 0 if validation passes
- Compilation fails if validation fails

TO COMPILE:
g++ -std=c++20 compile_time_validation.cpp -o compile_time_validation
./compile_time_validation


=== Compile-Time Validation Study ===
Example 1: 5 + 3 = 8
Message printed!
Example 2: x = 42

Example 3: Compile-time validation
Positive number: 5
✓ Validation passed at compile time!

Example 4: Real-world validation pattern
Processing 42 (PassThrough only)
✓ Config validation passed!

✓ All examples passed!


Summary: C++ Version Requirements

Our pattern needs: C++20 (for consteval)


Quick Reference

✅ Good Case (Passes):

❌ Bad Case (Fails):

To Experiment

Try uncommenting line 75 in the study file:
Then compile:
You'll see the compile error!