Support C++ 11 enum class generation via pure_enums=enum_class
Adds C++ 11 `enum class` generation to the C++ code generator. When `pure_enums=enum_class` is specified, generates strongly-typed enums with proper scoping and type safety.
## Code Generator Changes
**Modified `t_cpp_generator.cc`:**
- Added `gen_enum_class_` flag parsed from `pure_enums=enum_class` option
- Modified `generate_enum()` to emit `enum class` when both `gen_pure_enums_` and `gen_enum_class_` are set
- Fixed enum value scoping: use `static_cast<int>(Color::RED)` for array initialization
- Fixed map operations: cast enum class to int in `find()` calls (no implicit conversion)
**Test infrastructure:**
- Created `t_cpp_generator_enum_class_tests.cc` with three test cases validating default, `pure_enums`, and `pure_enums=enum_class` behavior
- Extracted common utilities to `t_cpp_generator_test_utils.h` (shared with `private_optional` tests)
- Added expected output files: `expected_Color_{default,pure_enums,enum_class}.txt`
**Build system:**
- Added CMake compile-checks for generated code (both `private_optional` and `enum_class`)
- Unified compile-check blocks with shared Boost detection
- Ensures generated code compiles as part of standard test build
## Usage
```thrift
enum Color {
RED = 1,
GREEN = 2,
BLUE = 3
}
```
```bash
thrift --gen cpp:pure_enums=enum_class example.thrift
```
Generates:
```cpp
enum class Color {
RED = 1,
GREEN = 2,
BLUE = 3
};
```
Backward compatible - existing behavior unchanged when option absent.
---
- [ ] Did you create an [Apache Jira](https://issues.apache.org/jira/projects/THRIFT/issues/) ticket? ([Request account here](https://selfserve.apache.org/jira-account.html), not required for trivial changes)
- [ ] If a ticket exists: Does your pull request title follow the pattern "THRIFT-NNNN: describe my issue"?
- [x] Did you squash your changes to a single commit? (not required, but preferred)
- [x] Did you do your best to avoid breaking changes? If one was needed, did you label the Jira ticket with "Breaking-Change"?
- [ ] If your change does not involve any code, include `[skip ci]` anywhere in the commit message to free up build resources.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: zsy056 <1074382+zsy056@users.noreply.github.com>diff --git a/compiler/cpp/tests/CMakeLists.txt b/compiler/cpp/tests/CMakeLists.txt
index 77c1524..468de6e 100644
--- a/compiler/cpp/tests/CMakeLists.txt
+++ b/compiler/cpp/tests/CMakeLists.txt
@@ -194,73 +194,117 @@
)
endif()
-# Compile-check generated C++ output for the fixture thrift file with private_optional enabled.
+# Compile-check generated C++ output for fixture thrift files.
# This ensures the generator output is compileable (no link step required).
+# Note: These checks require Boost headers and are optional.
if(TARGET thrift-compiler)
- # Generated C++ includes Thrift runtime headers which may require Boost.
- # Only enable the compile-check when Boost headers are available.
- set(_private_optional_boost_include_dirs "")
+ # Try to find Boost for the compile checks
find_package(Boost QUIET)
+ set(_compile_check_boost_include_dirs "")
if(Boost_FOUND)
- set(_private_optional_boost_include_dirs ${Boost_INCLUDE_DIRS})
+ set(_compile_check_boost_include_dirs ${Boost_INCLUDE_DIRS})
elseif(DEFINED BOOST_ROOT)
if(EXISTS "${BOOST_ROOT}/include/boost")
- set(_private_optional_boost_include_dirs "${BOOST_ROOT}/include")
+ set(_compile_check_boost_include_dirs "${BOOST_ROOT}/include")
elseif(EXISTS "${BOOST_ROOT}/boost")
- set(_private_optional_boost_include_dirs "${BOOST_ROOT}")
+ set(_compile_check_boost_include_dirs "${BOOST_ROOT}")
endif()
endif()
- if(_private_optional_boost_include_dirs STREQUAL "")
- message(STATUS "Skipping generated private_optional compile-check (Boost headers not found)")
+ # Only create compile-check targets if Boost is available
+ if(NOT _compile_check_boost_include_dirs STREQUAL "")
+ set(_private_optional_thrift
+ "${CMAKE_CURRENT_SOURCE_DIR}/cpp/test_private_optional.thrift"
+ )
+ set(_private_optional_gen_out_dir
+ "${CMAKE_CURRENT_BINARY_DIR}/generated-private-optional"
+ )
+ set(_private_optional_gen_cpp_dir
+ "${_private_optional_gen_out_dir}/gen-cpp"
+ )
+ set(_private_optional_types_cpp
+ "${_private_optional_gen_cpp_dir}/test_private_optional_types.cpp"
+ )
+
+ add_custom_command(
+ OUTPUT "${_private_optional_types_cpp}"
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${_private_optional_gen_out_dir}"
+ COMMAND ${CMAKE_COMMAND} -E chdir "${_private_optional_gen_out_dir}"
+ $<TARGET_FILE:thrift-compiler>
+ --gen cpp:private_optional
+ -o "${_private_optional_gen_out_dir}"
+ "${_private_optional_thrift}"
+ DEPENDS thrift-compiler "${_private_optional_thrift}"
+ VERBATIM
+ )
+
+ set_source_files_properties(
+ "${_private_optional_types_cpp}"
+ PROPERTIES GENERATED TRUE
+ )
+
+ add_library(thrift_compiler_generated_private_optional STATIC
+ "${_private_optional_types_cpp}"
+ )
+
+ target_include_directories(thrift_compiler_generated_private_optional PRIVATE
+ "${_private_optional_gen_cpp_dir}"
+ "${THRIFT_COMPILER_SOURCE_DIR}/../../lib/cpp/src"
+ "${CMAKE_CURRENT_BINARY_DIR}"
+ "${CMAKE_BINARY_DIR}"
+ ${_compile_check_boost_include_dirs}
+ )
+
+ set(_enum_class_thrift
+ "${CMAKE_CURRENT_SOURCE_DIR}/cpp/test_enum_class.thrift"
+ )
+ set(_enum_class_gen_out_dir
+ "${CMAKE_CURRENT_BINARY_DIR}/generated-enum-class"
+ )
+ set(_enum_class_gen_cpp_dir
+ "${_enum_class_gen_out_dir}/gen-cpp"
+ )
+ set(_enum_class_types_cpp
+ "${_enum_class_gen_cpp_dir}/test_enum_class_types.cpp"
+ )
+
+ add_custom_command(
+ OUTPUT "${_enum_class_types_cpp}"
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${_enum_class_gen_out_dir}"
+ COMMAND ${CMAKE_COMMAND} -E chdir "${_enum_class_gen_out_dir}"
+ $<TARGET_FILE:thrift-compiler>
+ --gen cpp:pure_enums=enum_class
+ -o "${_enum_class_gen_out_dir}"
+ "${_enum_class_thrift}"
+ DEPENDS thrift-compiler "${_enum_class_thrift}"
+ VERBATIM
+ )
+
+ set_source_files_properties(
+ "${_enum_class_types_cpp}"
+ PROPERTIES GENERATED TRUE
+ )
+
+ add_library(thrift_compiler_generated_enum_class STATIC
+ "${_enum_class_types_cpp}"
+ )
+
+ target_include_directories(thrift_compiler_generated_enum_class PRIVATE
+ "${_enum_class_gen_cpp_dir}"
+ "${THRIFT_COMPILER_SOURCE_DIR}/../../lib/cpp/src"
+ "${CMAKE_CURRENT_BINARY_DIR}"
+ "${CMAKE_BINARY_DIR}"
+ ${_compile_check_boost_include_dirs}
+ )
+
+ # Build the compile-check as part of the standard test build.
+ add_dependencies(thrift_compiler_tests thrift_compiler_generated_private_optional)
+ add_dependencies(thrift_compiler_tests thrift_compiler_generated_enum_class)
else()
- set(_private_optional_thrift
- "${CMAKE_CURRENT_SOURCE_DIR}/cpp/test_private_optional.thrift"
- )
- set(_private_optional_gen_out_dir
- "${CMAKE_CURRENT_BINARY_DIR}/generated-private-optional"
- )
- set(_private_optional_gen_cpp_dir
- "${_private_optional_gen_out_dir}/gen-cpp"
- )
- set(_private_optional_types_cpp
- "${_private_optional_gen_cpp_dir}/test_private_optional_types.cpp"
- )
-
- add_custom_command(
- OUTPUT "${_private_optional_types_cpp}"
- COMMAND ${CMAKE_COMMAND} -E make_directory "${_private_optional_gen_out_dir}"
- COMMAND ${CMAKE_COMMAND} -E chdir "${_private_optional_gen_out_dir}"
- $<TARGET_FILE:thrift-compiler>
- --gen cpp:private_optional
- -o "${_private_optional_gen_out_dir}"
- "${_private_optional_thrift}"
- DEPENDS thrift-compiler "${_private_optional_thrift}"
- VERBATIM
- )
-
- set_source_files_properties(
- "${_private_optional_types_cpp}"
- PROPERTIES GENERATED TRUE
- )
-
- add_library(thrift_compiler_generated_private_optional STATIC
- "${_private_optional_types_cpp}"
- )
-
- target_include_directories(thrift_compiler_generated_private_optional PRIVATE
- "${_private_optional_gen_cpp_dir}"
- "${THRIFT_COMPILER_SOURCE_DIR}/../../lib/cpp/src"
- "${CMAKE_CURRENT_BINARY_DIR}"
- "${CMAKE_BINARY_DIR}"
- ${_private_optional_boost_include_dirs}
- )
-
- # Build the compile-check as part of the standard test build.
- add_dependencies(thrift_compiler_tests thrift_compiler_generated_private_optional)
+ message(STATUS "Skipping generated code compile-checks (Boost headers not found)")
endif()
else()
- message(STATUS "Skipping generated private_optional compile-check (no thrift-compiler target)")
+ message(STATUS "Skipping generated code compile-checks (no thrift-compiler target)")
endif()
enable_testing()