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

编译期构造函数选择:GeoJSON position_t API实现技术问询

实现编译期构造的geojson::position_t<>解决方案

要实现你需要的多种构造方式,我们可以结合C的编译期重载解析、constexpr构造函数和类型约束(SFINAE或C20 Concepts)来完成,同时用std::variant让position_t<>能灵活存储点、线、多边形三种几何类型。下面是具体的实现方案:

核心实现思路

我们让position_t<>内部用std::variant存储不同的几何数据结构,然后为每种构造场景编写对应的constexpr构造函数,通过类型约束确保编译器在编译期就能选择正确的构造逻辑,避免重载冲突。

完整代码实现

#include <variant>
#include <vector>
#include <utility>
#include <type_traits>

namespace geojson {
template <typename Coord = double>
class position_t {
private:
    // 定义三种几何类型的内部存储
    using Point = std::pair<Coord, Coord>;
    using LineString = std::vector<position_t<Coord>>;
    using Polygon = std::vector<LineString>;

    std::variant<Point, LineString, Polygon> data_;

public:
    // 1. 构造点:直接传入两个坐标值
    constexpr position_t(Coord x, Coord y) noexcept 
        : data_(Point{std::move(x), std::move(y)}) {}

    // 2. 构造点:传入std::pair(支持任意可转换为Coord的pair类型)
    template <typename X, typename Y>
    requires std::is_convertible_v<X, Coord> && std::is_convertible_v<Y, Coord>
    constexpr position_t(const std::pair<X, Y>& p) noexcept 
        : data_(Point{static_cast<Coord>(p.first), static_cast<Coord>(p.second)}) {}

    // 完美转发版本,支持右值pair
    template <typename X, typename Y>
    requires std::is_convertible_v<X, Coord> && std::is_convertible_v<Y, Coord>
    constexpr position_t(std::pair<X, Y>&& p) noexcept 
        : data_(Point{static_cast<Coord>(std::move(p.first)), static_cast<Coord>(std::move(p.second))}) {}

    // 3. 构造线:传入多个position_t的初始化列表
    constexpr position_t(std::initializer_list<position_t<Coord>> points) noexcept 
        : data_(LineString{points.begin(), points.end()}) {}

    // 4. 构造多边形:传入嵌套的初始化列表(多个线环)
    constexpr position_t(std::initializer_list<std::initializer_list<position_t<Coord>>> rings) noexcept {
        Polygon poly;
        poly.reserve(rings.size());
        for (const auto& ring : rings) {
            poly.emplace_back(ring.begin(), ring.end());
        }
        data_ = std::move(poly);
    }

    // 辅助方法:判断当前存储的几何类型
    [[nodiscard]] constexpr bool is_point() const noexcept {
        return std::holds_alternative<Point>(data_);
    }

    [[nodiscard]] constexpr bool is_line_string() const noexcept {
        return std::holds_alternative<LineString>(data_);
    }

    [[nodiscard]] constexpr bool is_polygon() const noexcept {
        return std::holds_alternative<Polygon>(data_);
    }

    // 辅助方法:获取对应类型的数据(需确保当前类型匹配,否则会抛出std::bad_variant_access)
    template <typename T>
    [[nodiscard]] constexpr const T& get() const noexcept {
        return std::get<T>(data_);
    }

    template <typename T>
    [[nodiscard]] constexpr T& get() noexcept {
        return std::get<T>(data_);
    }
};
} // namespace geojson

代码解释与编译期逻辑

  1. 构造点的两种方式:

    • 直接传两个坐标值的构造函数会被point_1{10,12}和point_2(11,13)匹配,编译期就能完成点的构造。
    • 针对std::pair的构造函数用C20的requires约束(如果你用C17及以下,可以替换为std::enable_if),确保只有当传入的pair元素能转换为Coord类型时才启用,这样point_3(std::pair<int, int>(12,14))就能正确匹配并构造点。
  2. 构造线与多边形:

    • 接受std::initializer_list<position_t<Coord>>的构造函数会被line_1{ ... }匹配,自动将多个点组合成线。
    • 接受嵌套初始化列表的构造函数会被poly_1{ { ... }, { ... } }匹配,将多个线环组合成多边形,这一步也是编译期完成的(只要初始化列表是编译期常量)。
  3. 编译期安全:
    所有构造函数都是constexpr的,只要传入的参数是编译期常量,整个对象的构造过程会在编译期完成,完全符合你的编译期构造需求。同时,类型约束确保编译器不会在重载解析时出错,每个构造场景都有明确的匹配逻辑。

测试你的示例代码

现在你给出的示例代码可以直接编译运行:

int main() {
    // 点构造
    geojson::position_t<> point_1{ 10, 12 };
    geojson::position_t<> point_2( 11, 13 );
    geojson::position_t<> point_3(std::pair<int, int>(12, 14));

    // 线构造
    geojson::position_t<> line_1{ 
        geojson::position_t<> { 100, 120 }, 
        geojson::position_t<> { 110, 130 } 
    };

    // 多边形构造
    geojson::position_t<> poly_1{ 
        { geojson::position_t<> { 100, 120 }, geojson::position_t<> { 110, 130 }}, 
        { geojson::position_t<> { 101, 121 }, geojson::position_t<> { 111, 131 }} 
    };

    // 验证类型(可选)
    static_assert(point_1.is_point());
    static_assert(line_1.is_line_string());
    static_assert(poly_1.is_polygon());

    return 0;
}

兼容C++17的调整

如果你需要兼容C++17,把requires替换为std::enable_if即可,比如将pair的构造函数改成:

template <typename X, typename Y, 
          typename = std::enable_if_t<std::is_convertible_v<X, Coord> && std::is_convertible_v<Y, Coord>>>
constexpr position_t(const std::pair<X, Y>& p) noexcept 
    : data_(Point{static_cast<Coord>(p.first), static_cast<Coord>(p.second)}) {}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:39:37