如何获取C++模板参数成员变量type_id的列表?
Alright, let's tackle this problem step by step. We need to implement two key parts for the processor template class: the get_type_ids function that collects all the type_id values from the template parameters, and a type-checking mechanism to ensure only valid base_type derivatives are passed to process.
1. Implementing get_type_ids
This is straightforward with C++11's parameter pack expansion. We can directly initialize a std::vector<uint64_t> using the type_id static members of each template argument:
std::vector<uint64_t> get_type_ids() const { return {Args::type_id...}; }
The ... expands the template parameter pack Args into a comma-separated list of Args::type_id values, which the vector's initializer list constructor uses to populate the container.
2. Adding Type-Checking for process
To make the type check efficient and reusable, we'll store the allowed type_id values in an std::unordered_set (for O(1) average lookup time) as a private member of the processor class. Then, we'll add helper functions to validate each argument before processing.
Here's the complete, working implementation:
#include <iostream> #include <vector> #include <unordered_set> #include <type_traits> struct base_type { static const uint64_t type_id = 0x0; }; struct A : public base_type { static const uint64_t type_id = 0xA; }; struct B : public base_type { static const uint64_t type_id = 0xB; }; struct C : public base_type { static const uint64_t type_id = 0xC; }; template <class... Args> struct processor { private: // Store allowed type IDs for fast lookup const std::unordered_set<uint64_t> allowed_types_{Args::type_id...}; // Helper to check a single object's type ID bool is_type_allowed(const base_type& obj) const { // Use count() for pre-C++20 compatibility; contains() works in C++20+ return allowed_types_.count(obj.type_id) > 0; } // C++11-compatible recursive check for all arguments bool check_all() const { return true; } template <class First, class... Rest> bool check_all(const First& first, const Rest&... rest) const { static_assert(std::is_base_of<base_type, typename std::decay<First>::type>::value, "Argument must derive from base_type"); return is_type_allowed(first) && check_all(rest...); } public: std::vector<uint64_t> get_type_ids() const { return {Args::type_id...}; } void process(const base_type&... args) const { // Validate all arguments if (!check_all(args...)) { std::cout << "One of the arguments to process was not the correct type" << std::endl; return; } // Safe to process arguments here - add your custom logic below std::cout << "Processing valid arguments:" << std::endl; ((std::cout << " Type ID: 0x" << std::hex << args.type_id << std::endl), ...); } }; int main() { processor<A, B> my_processor; B b; C c; // This will trigger the error message since C's type_id isn't allowed my_processor.process(b, c); // Uncomment to test valid arguments // A a; // my_processor.process(a, b); }
Key Details:
- Efficient Lookup: Using
std::unordered_setensures that checking each type ID is fast, even with many template parameters. - Compile-Time Safety: The
static_assertincheck_allensures that onlybase_typederivatives are passed toprocess, catching invalid types at compile time instead of runtime. - C++11 Compatibility: The recursive
check_allfunction works with C11. If you're using C17 or later, you can simplify this with a fold expression:bool all_allowed = (is_type_allowed(args) && ...); - Flexible Error Handling: We've kept the error message matching your example, but you could also throw an exception for stricter error handling if needed.
When you run this code, it will output the expected error message because C's type_id isn't in the allowed set for processor<A, B>.
内容的提问来源于stack exchange,提问作者Nick Chapman

