// ============================================================================
// COMPLETE C++ TUPLE TUTORIAL
// ============================================================================
#include <tuple>
#include <iostream>
#include <string>
#include <typeinfo>
// ============================================================================
// PART 1: BASIC TUPLE CONCEPTS
// ============================================================================
void basic_tuple_usage() {
std::cout << "=== PART 1: Basic Tuple Usage ===" << std::endl;
// Creating tuples with values
std::tuple<int, float, std::string> data1 = {42, 3.14f, "hello"};
std::tuple<int, float, std::string> data2(100, 2.5f, "world");
auto data3 = std::make_tuple(200, 1.5f, "auto");
// Accessing elements
int first = std::get<0>(data1); // Gets 42
float second = std::get<1>(data1); // Gets 3.14f
std::string third = std::get<2>(data1); // Gets "hello"
std::cout << "data1: " << first << ", " << second << ", " << third << std::endl;
// Modifying elements
std::get<0>(data1) = 999;
std::cout << "Modified data1[0]: " << std::get<0>(data1) << std::endl;
// Tuple size
constexpr size_t size = std::tuple_size_v<decltype(data1)>;
std::cout << "Tuple size: " << size << std::endl;
}
// ============================================================================
// PART 2: TUPLES WITH DIFFERENT SIZES
// ============================================================================
void different_tuple_sizes() {
std::cout << "\n=== PART 2: Different Tuple Sizes ===" << std::endl;
std::tuple<int> single = {10}; // 1 element
std::tuple<int, int> pair = {20, 30}; // 2 elements
std::tuple<int, int, int> triple = {40, 50, 60}; // 3 elements
std::tuple<int, int, int, int, int> quintuple = {1, 2, 3, 4, 5}; // 5 elements
std::cout << "Single: " << std::get<0>(single) << std::endl;
std::cout << "Pair: " << std::get<0>(pair) << ", " << std::get<1>(pair) << std::endl;
std::cout << "Triple: " << std::get<0>(triple) << ", " << std::get<1>(triple) << ", " << std::get<2>(triple) << std::endl;
std::cout << "Quintuple[4]: " << std::get<4>(quintuple) << std::endl;
// Tuple sizes
std::cout << "Sizes: " << std::tuple_size_v<decltype(single)> << ", "
<< std::tuple_size_v<decltype(pair)> << ", "
<< std::tuple_size_v<decltype(triple)> << ", "
<< std::tuple_size_v<decltype(quintuple)> << std::endl;
}
// ============================================================================
// PART 3: MIXED TYPE TUPLES
// ============================================================================
void mixed_type_tuples() {
std::cout << "\n=== PART 3: Mixed Type Tuples ===" << std::endl;
// Different types in same tuple
std::tuple<int, float, double, char, bool, std::string> mixed = {
42, 3.14f, 2.718, 'A', true, "mixed"
};
std::cout << "Mixed tuple contents:" << std::endl;
std::cout << "int: " << std::get<0>(mixed) << std::endl;
std::cout << "float: " << std::get<1>(mixed) << std::endl;
std::cout << "double: " << std::get<2>(mixed) << std::endl;
std::cout << "char: " << std::get<3>(mixed) << std::endl;
std::cout << "bool: " << std::get<4>(mixed) << std::endl;
std::cout << "string: " << std::get<5>(mixed) << std::endl;
}
// ============================================================================
// PART 4: TUPLE_ELEMENT_T - EXTRACTING TYPES (NOT VALUES)
// ============================================================================
void tuple_element_type_extraction() {
std::cout << "\n=== PART 4: Type Extraction with std::tuple_element_t ===" << std::endl;
// Define a tuple TYPE (no actual values stored)
using MyTupleType = std::tuple<int, float, double, std::string>;
// Extract individual types from the tuple
using FirstType = std::tuple_element_t<0, MyTupleType>; // int
using SecondType = std::tuple_element_t<1, MyTupleType>; // float
using ThirdType = std::tuple_element_t<2, MyTupleType>; // double
using FourthType = std::tuple_element_t<3, MyTupleType>; // std::string
// Use the extracted types to create variables
FirstType var1 = 100; // int var1 = 100;
SecondType var2 = 2.5f; // float var2 = 2.5f;
ThirdType var3 = 3.14159; // double var3 = 3.14159;
FourthType var4 = "extracted"; // std::string var4 = "extracted";
std::cout << "Variables created from extracted types:" << std::endl;
std::cout << "var1 (int): " << var1 << std::endl;
std::cout << "var2 (float): " << var2 << std::endl;
std::cout << "var3 (double): " << var3 << std::endl;
std::cout << "var4 (string): " << var4 << std::endl;
// Show type information
std::cout << "Type information:" << std::endl;
std::cout << "FirstType: " << typeid(FirstType).name() << std::endl;
std::cout << "SecondType: " << typeid(SecondType).name() << std::endl;
std::cout << "ThirdType: " << typeid(ThirdType).name() << std::endl;
std::cout << "FourthType: " << typeid(FourthType).name() << std::endl;
}
// ============================================================================
// PART 5: TUPLES IN TEMPLATES
// ============================================================================
template <typename TupleType>
class TupleProcessor {
public:
// Extract types from the tuple
using FirstType = std::tuple_element_t<0, TupleType>;
using SecondType = std::tuple_element_t<1, TupleType>;
static constexpr size_t tuple_size = std::tuple_size_v<TupleType>;
void process() {
std::cout << "Processing tuple with " << tuple_size << " elements" << std::endl;
// Create variables using extracted types
FirstType first_var{}; // Default initialize
SecondType second_var{};
std::cout << "FirstType size: " << sizeof(FirstType) << " bytes" << std::endl;
std::cout << "SecondType size: " << sizeof(SecondType) << " bytes" << std::endl;
}
};
void tuples_in_templates() {
std::cout << "\n=== PART 5: Tuples in Templates ===" << std::endl;
// Different tuple types
using IntFloatTuple = std::tuple<int, float>;
using DoubleCharTuple = std::tuple<double, char>;
using StringBoolTuple = std::tuple<std::string, bool>;
// Create template instances with different tuple types
TupleProcessor<IntFloatTuple> processor1;
TupleProcessor<DoubleCharTuple> processor2;
TupleProcessor<StringBoolTuple> processor3;
processor1.process();
processor2.process();
processor3.process();
}
// ============================================================================
// PART 6: ADVANCED TUPLE TECHNIQUES
// ============================================================================
// Template that can handle tuples of any size
template <typename TupleType>
class FlexibleTupleHandler {
public:
static constexpr size_t size = std::tuple_size_v<TupleType>;
// Always safe - every tuple has at least element 0
using FirstType = std::tuple_element_t<0, TupleType>;
// Conditional type extraction (C++17 feature)
using SecondType = std::conditional_t<
(size >= 2),
std::tuple_element_t<1, TupleType>,
void // If tuple has less than 2 elements, use void
>;
void analyze_tuple() {
std::cout << "Tuple analysis:" << std::endl;
std::cout << " Size: " << size << std::endl;
std::cout << " FirstType size: " << sizeof(FirstType) << " bytes" << std::endl;
if constexpr (size >= 2) {
std::cout << " SecondType size: " << sizeof(SecondType) << " bytes" << std::endl;
} else {
std::cout << " No second element" << std::endl;
}
}
};
void advanced_tuple_techniques() {
std::cout << "\n=== PART 6: Advanced Tuple Techniques ===" << std::endl;
// Test with different sized tuples
FlexibleTupleHandler<std::tuple<int>> handler1; // 1 element
FlexibleTupleHandler<std::tuple<int, float>> handler2; // 2 elements
FlexibleTupleHandler<std::tuple<int, float, double>> handler3; // 3 elements
handler1.analyze_tuple();
handler2.analyze_tuple();
handler3.analyze_tuple();
}
// ============================================================================
// PART 7: PRACTICAL EXAMPLE - TYPE-BASED CONFIGURATION
// ============================================================================
// Define some configuration "types" (like layouts in GPU programming)
struct FastConfig { static constexpr const char* name = "Fast"; };
struct SmallConfig { static constexpr const char* name = "Small"; };
struct PreciseConfig { static constexpr const char* name = "Precise"; };
template <typename ConfigTuple>
class ConfigurableProcessor {
public:
using DataType = std::tuple_element_t<0, ConfigTuple>; // First: data type
using SpeedConfig = std::tuple_element_t<1, ConfigTuple>; // Second: speed config
using MemoryConfig = std::tuple_element_t<2, ConfigTuple>; // Third: memory config
void run() {
std::cout << "Running processor with:" << std::endl;
std::cout << " DataType size: " << sizeof(DataType) << " bytes" << std::endl;
std::cout << " Speed: " << SpeedConfig::name << std::endl;
std::cout << " Memory: " << MemoryConfig::name << std::endl;
}
};
void practical_example() {
std::cout << "\n=== PART 7: Practical Example ===" << std::endl;
// Different configurations using tuples
using Config1 = std::tuple<float, FastConfig, SmallConfig>;
using Config2 = std::tuple<double, PreciseConfig, FastConfig>;
using Config3 = std::tuple<int, SmallConfig, PreciseConfig>;
ConfigurableProcessor<Config1> processor1;
ConfigurableProcessor<Config2> processor2;
ConfigurableProcessor<Config3> processor3;
std::cout << "Configuration 1:" << std::endl;
processor1.run();
std::cout << "Configuration 2:" << std::endl;
processor2.run();
std::cout << "Configuration 3:" << std::endl;
processor3.run();
}
// ============================================================================
// PART 8: TUPLE UNPACKING AND STRUCTURED BINDINGS (C++17)
// ============================================================================
void tuple_unpacking() {
std::cout << "\n=== PART 8: Tuple Unpacking ===" << std::endl;
std::tuple<int, float, std::string> data = {42, 3.14f, "hello"};
// C++17 structured binding - unpack tuple into separate variables
auto [number, decimal, text] = data;
std::cout << "Unpacked values:" << std::endl;
std::cout << "number: " << number << std::endl;
std::cout << "decimal: " << decimal << std::endl;
std::cout << "text: " << text << std::endl;
// Modify unpacked variables (they're copies)
number = 999;
std::cout << "Modified number: " << number << std::endl;
std::cout << "Original tuple[0]: " << std::get<0>(data) << std::endl;
}
// ============================================================================
// MAIN FUNCTION - RUN ALL EXAMPLES
// ============================================================================
int main() {
std::cout << "C++ TUPLE COMPREHENSIVE TUTORIAL (MareArts)" << std::endl;
std::cout << "=================================" << std::endl;
basic_tuple_usage();
different_tuple_sizes();
mixed_type_tuples();
tuple_element_type_extraction();
tuples_in_templates();
advanced_tuple_techniques();
practical_example();
tuple_unpacking();
std::cout << "\n=== SUMMARY ===" << std::endl;
std::cout << "1. Tuples can hold any number of elements (1, 2, 3, 5, 10...)" << std::endl;
std::cout << "2. Tuples can store VALUES or define TYPES" << std::endl;
std::cout << "3. std::get<N>(tuple) accesses values" << std::endl;
std::cout << "4. std::tuple_element_t<N, TupleType> extracts types" << std::endl;
std::cout << "5. Templates + tuples = powerful type-based programming" << std::endl;
std::cout << "6. Perfect for configuration systems and generic programming" << std::endl;
return 0;
}
// ============================================================================
// KEY TAKEAWAYS:
// ============================================================================
//
// 1. TUPLE BASICS:
// - std::tuple<T1, T2, T3> can hold any types
// - Access with std::get<0>(tuple), std::get<1>(tuple), etc.
// - Size with std::tuple_size_v<TupleType>
//
// 2. TYPE EXTRACTION:
// - std::tuple_element_t<N, TupleType> gets the Nth type
// - Used at compile-time, not runtime
// - Perfect for template programming
//
// 3. TEMPLATE USAGE:
// - Tuples as template parameters enable type-based configuration
// - One template + multiple tuple types = multiple specialized classes
// - Compiler generates different code for each tuple type
//
// 4. FLEXIBILITY:
// - Any tuple size works
// - Mix any types in same tuple
// - Conditional type extraction for varying sizes
//
// 5. PRACTICAL APPLICATIONS:
// - Configuration systems (data type + algorithm choice)
// - Generic programming (same code, different types)
// - Type-safe parameter passing
// - Template specialization without code duplication
No comments:
Post a Comment