用不同的别名编译相同的来源

发布于 2025-02-05 14:07:27 字数 1631 浏览 3 评论 0原文

tldr:您可以用定义不同别名的不同标头编译相同的源代码吗?

我创建了一个库,其中一组功能使用标题中的几个别名类型编码。

algorithm_2d.h

using Point = Eigen::Vector2d;
using Vector = Eigen::Vector2d;

algorithm.cpp

Vector& scale_vector(
    Vector &v,
    double s)
{
    double len = v.norm();
    if (len != 0.0) { v *= s/len;}
    return v;
}

double distance_between_points(
    Point const &p1,
    Point const &p2)
{
    return (p2 - p1).norm();
}

现在我想编译相同的algorithm.cpp,但具有不同的别名:

algorithm_3d.h << /code>

using Point = Eigen::Vector3d;
using Vector = Eigen::Vector3d;

我正在使用cmake使用pybind11构建,因为这主要是python库。

我宁愿不必使用模板,因为这会导致我必须在每个功能中定义每种类型。正如您在摘要中看到的那样,它将使其读取率降低,这已经是一种数学上复杂的算法(未显示的其余代码)。

编辑:

另一个示例,以清楚使用这些别名。如果我使用模板,则每次此功能都称为

.h

using PointSet = std::vector<Point, Eigen::aligned_allocator<Point> >;

.cpp

Vector compute_left_tangent(
    PointSet const &pts,
    int end,
{
    Vector tHat1 = PointSet[end+1] - PointSet[end];
    tHat1 = tHat / distance_between_points(PoinSet[end],PointSet[end+1]) 
}

我不想添加&lt; eigen :: vector2d, ...等等,每次我称之为这些功能之一。也许有一种方法可以使用我缺少的模板?

TLDR: Can you compile the same source code with different headers defining diffrent aliases?

I have created a library, with a set of functions coded using a couple of aliased type in the header.

algorithm_2d.h

using Point = Eigen::Vector2d;
using Vector = Eigen::Vector2d;

algorithm.cpp

Vector& scale_vector(
    Vector &v,
    double s)
{
    double len = v.norm();
    if (len != 0.0) { v *= s/len;}
    return v;
}

double distance_between_points(
    Point const &p1,
    Point const &p2)
{
    return (p2 - p1).norm();
}

Now I would like to compile the same algorithm.cpp but with different aliases:

algorithm_3d.h

using Point = Eigen::Vector3d;
using Vector = Eigen::Vector3d;

I am building using CMake with pybind11 as this is mainly a python library.

I would prefer not having to use templates, as that would cause me to have to define every single type in every function. And as you can see in the snippet, it would make it a lot less readable, and this is already a mathematically complicated algorithm (rest of the code not shown).

EDIT:

Another example to make it clear what I mean by using the aliases. If I were using templates, each time this function is called

.h

using PointSet = std::vector<Point, Eigen::aligned_allocator<Point> >;

.cpp

Vector compute_left_tangent(
    PointSet const &pts,
    int end,
{
    Vector tHat1 = PointSet[end+1] - PointSet[end];
    tHat1 = tHat / distance_between_points(PoinSet[end],PointSet[end+1]) 
}

I don't want to have to add the <Eigen::Vector2d,..., etc> every time I call one of these functions. Maybe there is a way of doing this with templates that I am missing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

断念 2025-02-12 14:07:27

给定以下模板文件:(调用algorithm.cpp.tmpl

using Point = @_flavor@;
using Vector = @_flavor@;
#include "algorithm.cpp"

您可以使Cmake生成风味自动生成风味,并作为some_target的一部分构建它们:

set(FLAVORS Eigen::Vector2d Eigen::Vector3d)
foreach(_flavor ${FLAVORS})
  string(MAKE_C_IDENTIFIER ${_flavor} _flavor_slug)
  set(_flavor_out algorithm_${_flavor_slug}.cpp)
  configure_file(algorithm.cpp.tmpl ${_flavor_out} @ONLY)
  target_sources(some_target PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/${_flavor_out})
endforeach()

Given the following template file: (call it algorithm.cpp.tmpl)

using Point = @_flavor@;
using Vector = @_flavor@;
#include "algorithm.cpp"

You can have CMake generate flavors automatically and build them as part of some_target:

set(FLAVORS Eigen::Vector2d Eigen::Vector3d)
foreach(_flavor ${FLAVORS})
  string(MAKE_C_IDENTIFIER ${_flavor} _flavor_slug)
  set(_flavor_out algorithm_${_flavor_slug}.cpp)
  configure_file(algorithm.cpp.tmpl ${_flavor_out} @ONLY)
  target_sources(some_target PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/${_flavor_out})
endforeach()
东走西顾 2025-02-12 14:07:27

当然,这是编译器定义的一种用途。

algorithm.h

 #ifdef 2D
    using Point = Eigen::Vector2d; using Vector = Eigen::Vector2d;
 #endif
 #ifdef 3D   
   using Point = Eigen::Vector3d; using Vector = Eigen::Vector3d;
 #endif

algorithm.cpp

Vector& scale_vector(
    Vector &v,
    double s) {
    double len = v.norm();
    if (len != 0.0) { v *= s/len;}
    return v; }

double distance_between_points(
    Point const &p1,
    Point const &p2) {
    return (p2 - p1).norm(); }

另请参阅
https://en.cppreference.com/w/cpp/cpp/preprecessor/preprocessor/conditional

现在,您只需要告诉编译器定义2D或3D即可。

G ++ -D3D ...

我认为Microsoft编译器使用Somtehing
/d3d

Sure, this is one use of compiler defines are for.

algorithm.h

 #ifdef 2D
    using Point = Eigen::Vector2d; using Vector = Eigen::Vector2d;
 #endif
 #ifdef 3D   
   using Point = Eigen::Vector3d; using Vector = Eigen::Vector3d;
 #endif

algorithm.cpp

Vector& scale_vector(
    Vector &v,
    double s) {
    double len = v.norm();
    if (len != 0.0) { v *= s/len;}
    return v; }

double distance_between_points(
    Point const &p1,
    Point const &p2) {
    return (p2 - p1).norm(); }

See also
https://en.cppreference.com/w/cpp/preprocessor/conditional

Now you just need to tell your compiler to define 2D or 3D.

g++ -D3D ...

I think the microsoft compiler uses somtehing like
/D3D

酒浓于脸红 2025-02-12 14:07:27

模板是您的朋友。没有问题,您会担心:

我宁愿不必使用模板,因为这会导致我
必须定义每个功能中的每种类型

必须在每个功能

我不想添加&lt; eigen :: vector2d,...等每次
我称这些功能之一。

template参数参数ducact 在这里做所有需要的工作。

例如:

template <typename T>
T& scale_vector(
    T& v,
    double s)
{
    double len = v.norm();
    if (len != 0.0) {
        v *= s / len;
    }
    return v;
}

template <typename T>
double distance_between_points(
    const T& p1,
    const T& p2)
{
    return (p2 - p1).norm();
}

template <typename T>
using PointSet = std::vector<T, Eigen::aligned_allocator<T>>;

template <typename T>
auto compute_left_tangent(
    PointSet<T> const& pts,
    int end)
{
    auto tHat1 = pts[end + 1] - pts[end];
    return tHat1 / distance_between_points(pts[end], pts[end + 1]);
}

void test_scale_vector()
{
    Eigen::Vector2d v2d { 1.2, 0.3 };
    scale_vector(v2d, 3.0);
    std::cout << "v2d:\n"
              << v2d << '\n';

    Eigen::Vector3d v3d { 1.2, 0.3, -0.22 };
    scale_vector(v3d, 3.0);
    std::cout << "\nv3d:\n"
              << v3d << '\n';
}

void test_distance_between_points()
{
    std::cout << "\ndistance 2d = " << distance_between_points(Eigen::Vector2d { 1.0, 2.0 }, { -1.0, -1.0 }) << '\n';
    std::cout << "distance 3d = " << distance_between_points(Eigen::Vector3d { 1.0, 2.0, 0.0 }, { -1.0, -1.0, -2.0 }) << '\n';
}

void test_compute_left_tangent()
{
    auto v2 = PointSet<Eigen::Vector2d> { { 1.0, -0.5 }, { 0.0, 0.0 }, { -1.5, 0.5 }, { -2.0, 2.0 } };
    std::cout << "\ncompute_left_tangent 2d:\n"
              << compute_left_tangent(v2, 1) << '\n';

    auto v3 = PointSet<Eigen::Vector3d> { { 1.0, -0.5, 0.0 }, { 0.0, 0.0, 0.0 }, { -1.5, 0.5, 0.2 }, { -2.0, 2.0, 0.5 } };
    std::cout << "\ncompute_left_tangent 3d:\n"
              << compute_left_tangent(v3, 1) << '\n';
}

live demo

没有代码生成器,没有宏,否#ifdef #ifdef s。

或者,如果您喜欢更限制的模板定义(因此仅适用于eigen):此示例也很好地工作

如果您还有其他疑问,请以无法编译或无法正确运行的代码形式陈述它们。您可以从上面提供的Godbolt上的示例开始。

Template is your friend here. There are no problem you are so worry about:

I would prefer not having to use templates, as that would cause me to
have to define every single type in every function

And

I don't want to have to add the <Eigen::Vector2d,..., etc> every time
I call one of these functions.

Template argument deduction does all needed work here.

For example:

template <typename T>
T& scale_vector(
    T& v,
    double s)
{
    double len = v.norm();
    if (len != 0.0) {
        v *= s / len;
    }
    return v;
}

template <typename T>
double distance_between_points(
    const T& p1,
    const T& p2)
{
    return (p2 - p1).norm();
}

template <typename T>
using PointSet = std::vector<T, Eigen::aligned_allocator<T>>;

template <typename T>
auto compute_left_tangent(
    PointSet<T> const& pts,
    int end)
{
    auto tHat1 = pts[end + 1] - pts[end];
    return tHat1 / distance_between_points(pts[end], pts[end + 1]);
}

void test_scale_vector()
{
    Eigen::Vector2d v2d { 1.2, 0.3 };
    scale_vector(v2d, 3.0);
    std::cout << "v2d:\n"
              << v2d << '\n';

    Eigen::Vector3d v3d { 1.2, 0.3, -0.22 };
    scale_vector(v3d, 3.0);
    std::cout << "\nv3d:\n"
              << v3d << '\n';
}

void test_distance_between_points()
{
    std::cout << "\ndistance 2d = " << distance_between_points(Eigen::Vector2d { 1.0, 2.0 }, { -1.0, -1.0 }) << '\n';
    std::cout << "distance 3d = " << distance_between_points(Eigen::Vector3d { 1.0, 2.0, 0.0 }, { -1.0, -1.0, -2.0 }) << '\n';
}

void test_compute_left_tangent()
{
    auto v2 = PointSet<Eigen::Vector2d> { { 1.0, -0.5 }, { 0.0, 0.0 }, { -1.5, 0.5 }, { -2.0, 2.0 } };
    std::cout << "\ncompute_left_tangent 2d:\n"
              << compute_left_tangent(v2, 1) << '\n';

    auto v3 = PointSet<Eigen::Vector3d> { { 1.0, -0.5, 0.0 }, { 0.0, 0.0, 0.0 }, { -1.5, 0.5, 0.2 }, { -2.0, 2.0, 0.5 } };
    std::cout << "\ncompute_left_tangent 3d:\n"
              << compute_left_tangent(v3, 1) << '\n';
}

Live demo

No code generators, no macros, no #ifdefs.

Or if you prefer to more restrictive templates definition (so works only with Eigen): this example works nicely too.

If you have any additional doubts please state them in form of code which do not compile or do not run properly. You can start from my examples on godbolt provided above.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文