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 ✅








No comments:

Post a Comment