You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在保留概念约束的前提下实现State::Machine模板的单Map参数实例化?

Simplifying State::Machine Instantiation to a Single Map Parameter (With Full Concept Constraints)

Absolutely! You can retain all your concept-based type constraints while simplifying State::Machine instantiation down to just passing your map type (or even letting the compiler deduce it automatically) using C++20 features like Class Template Argument Deduction (CTAD) and type extraction from standard container associated types. Here's a step-by-step solution:

1. Refine Concepts for Type Extraction

First, adjust your core concepts to support extracting types directly from your map and transition objects:

  • Update your Map concept to require standard container associated types (key_type and mapped_type), so we can pull out constraint and transition container types straight from the map.
  • For the Transition concept, ensure we can deduce the input source type and result types from the State::Product return value using std::invoke_result_t and decltype.
// Refined core concepts
template <typename M>
concept Map = requires(M m) {
    typename M::key_type;
    typename M::mapped_type;
    // Add your existing Map concept constraints here
};

template <typename T, typename S, typename C, typename R>
concept Transition = requires(T t, S s) {
    { t(s) } -> std::convertible_to<State::Product<S, C, R>>;
};

template <typename Trs, typename T>
concept RangeOfTransition = requires(Trs trs) {
    typename Trs::value_type;
    requires Transition<typename Trs::value_type, T, /* Deduce remaining types */>;
    // Add your existing Range::Of constraints here
};

2. Redesign State::Machine for Single-Parameter Use

Rewrite the Machine template to accept only a map type (plus optional strategy) and extract all required types from the map. We'll use static assertions to enforce all original concept constraints:

namespace State {
enum Strategy { Breadth, Depth, Heuristic };

template <Map M, Strategy S = Strategy::Depth>
class Machine {
public:
    // Extract core types directly from the map
    using Constraint = typename M::key_type;
    using Transitions = typename M::mapped_type;
    using Transition = typename Transitions::value_type;

    // Extract source/result types from the transition's State::Product return value
    using Product = std::invoke_result_t<Transition, /* Deduce source type */>;
    using Source = decltype(std::declval<Product>().source);
    using Result = decltype(std::declval<Product>().product);

    // Enforce all original concept constraints
    static_assert(Range::Type<Source>, "Source must satisfy Range::Type concept");
    static_assert(Comparable<Constraint>, "Constraint must satisfy Comparable concept");
    static_assert(Transition<Transition, Source, Constraint, Result>, "Transition must meet Transition concept requirements");
    static_assert(Range::Of<Transition, Transitions>, "Transitions must be a valid range of Transition objects");

    // Constructor to accept the map instance
    explicit Machine(M map) : map_(std::move(map)) {}

private:
    M map_;
};

// CTAD Deduction Guide: Let the compiler automatically deduce the map type
template <Map M>
Machine(M) -> Machine<M>;
} // namespace State

Key Details:

  • Constraint comes from the map's key_type, and Transitions from its mapped_type.
  • Source and Result are pulled directly from the State::Product returned by your transition—no need to modify State::Product unless you want to add nested type aliases for cleaner code.
  • Static assertions ensure none of your original concept safety is lost.

3. Simplified Instantiation

Now you can instantiate State::Machine exactly how you wanted—either explicitly passing the map type, or letting CTAD handle it automatically:

// Your existing transition and map setup
auto transition = [](std::string source) {
    return State::Product<std::string, State, State> {
        .source = source,
        .state = State::Start,
        .product = State::Start,
    };
};
std::map<State, std::set<decltype(transition)>> map = {{State::Start, {transition}}};

// Option 1: Explicitly pass the map type (matches your desired syntax)
State::Machine<decltype(map)> machine(map);

// Option 2: Let CTAD deduce the map type automatically (even cleaner!)
State::Machine machine(map);

This approach keeps all your type safety from concepts while drastically simplifying the instantiation process. It works seamlessly with C++20-compliant compilers (GCC 10+, Clang 11+, MSVC 2019+).

内容的提问来源于stack exchange,提问作者Robbie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 01:22:35