.
// 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
}
No comments:
Post a Comment