【问题标题】:Template metaprogramming - trying to implement Dimensional Analysis模板元编程 - 尝试实现维度分析
【发布时间】:2020-07-06 12:02:30
【问题描述】:

为了更好地理解和学习,我尝试使用 boost mp11 库来实现《C++ 模板元编程》一书中的维度分析(也可以在 boost mpl 库的文档中找到)。一个原因是 C++11 具有本书编写时不可用的特性,而这些特性现在非常有用。

我正在使用 Visual Studio 2019 社区版。

在我不得不实现 operator* 之前一切都很顺利。我无法执行用于 mpl 库的技巧。 Operator+ 运行良好,所以问题必须与书中指出的问题相似,但应该有不同的解决方案。请帮我找到它。

(最短的)示例代码如下。它被编译并正确运行。当最后 3 行未注释时,会出现错误:

错误 C2676: binary '*': 'quantity' 未定义此运算符或转换为预定义运算符可接受的类型

由于某种原因,operator* 是不可见的,而类似的 operator+ 是。

谢谢

#include <iostream>

typedef std::integer_sequence<int, 1, 0, 0, 0, 0, 0, 0> mass;
typedef std::integer_sequence<int, 0, 1, 0, 0, 0, 0, 0> length;
typedef std::integer_sequence<int, 0, 0, 1, 0, 0, 0, 0> time;

typedef std::integer_sequence<int, 0, 1, -1, 0, 0, 0, 0> velocity;
typedef std::integer_sequence<int, 0, 1, -2, 0, 0, 0, 0> acceleration;
typedef std::integer_sequence<int, 1, 1, -2, 0, 0, 0, 0> force;


template<typename T, typename D>
struct quantity
{
    template<typename D1>
    quantity(const quantity<T, D1>& oOther) :
        m_value(oOther.m_value())
    {
        static_assert(std::is_same<D, D1>::value, "Type mismatch");
    }

    explicit quantity(T x) :
        m_value(x)
    {
    }

    T value() const
    {
        return m_value;
    }

    private:
        T m_value;
};


template
<
    template<class... A> class F,
    class... L
>
struct mp_transform_impl;

template
<
    template<class...> class F,
    template<class...> class L1,
    class... T1,
    template<class...> class L2,
    class... T2
>
struct mp_transform_impl<F, L1<T1...>, L2<T2...>>
{
    using type = L1<F<T1, T2>...>;
};

template<template<class...> class F, class... L>
using mp_transform = typename mp_transform_impl<F, L...>::type;


template<class... T>
struct mp_plus_impl;

template<>
struct mp_plus_impl<>
{
    using type = std::integral_constant<int, 0>;
};

template<class T1, class... T>
struct mp_plus_impl<T1, T...>
{
    static constexpr auto _v = T1::value + mp_plus_impl<T...>::type::value;
    using type = std::integral_constant<typename std::remove_const<decltype(_v)>::type, _v>;
};

template<class... T>
using mp_plus = typename mp_plus_impl<T...>::type;


template<typename T, typename D>
quantity<T, D> operator+(quantity<T, D> x, quantity<T, D> y)
{
    return quantity<T, D>(x.value() + y.value());
}

template<typename T, typename D1, typename D2>
quantity
<
    T,
    typename mp_transform<mp_plus, D1, D2>::type
>
operator*(quantity<T, D1> x, quantity<T, D2> y)
{
    using dim = typename mp_transform<mp_plus, D1, D2>::type;
    return quantity<T, dim>(x.value() * y.value());
}


int main(int argc, char* argv[])
{
    auto len1 = quantity<double, length>(4.5);
    auto len2 = quantity<double, length>(3.5);
    std::cout <<
        "Sum: " <<
        (len1 + len2).value() <<
        std::endl;

    auto m = quantity<double, mass>(5.0);
    auto a = quantity<double, acceleration>(9.815);

    // error C2676:  binary '*': 'quantity<double,mass>' does not define this operator
    // or a conversion to a type acceptable to the predefined operator
    //std::cout <<
    //    "Product: " <<
    //    (m * a).value() << std::endl;
    return 0;
}

【问题讨论】:

  • "由于某种原因,operator* 是不可见的,而类似的 operator+ 是"。它不是隐形的。只是与您提供的参数匹配的模板特化根本不存在,尽管编译器已尽最大努力创建它。

标签: c++ boost-mpl boost-mp11


【解决方案1】:

代码存在多个问题。在修复了一些(但不是全部)之后,这是一个工作版本:https://godbolt.org/z/3B9Sc4


以下是一些修改:

  1. std::integral_constant 的使用是不必要的。您可以简单地使用constexpr ints。这可以显着简化您的mp_plus,并且:

  2. mp_transform_impl 中的模板参数是不必要的复杂。始终使用 std::integer_sequence&lt;int, ...&gt; 时,您不需要类 L1L2

  3. 使用您的mp_transform,您无需添加typename ::type

【讨论】:

  • 非常感谢。我从这个解决方案中学到了很多。这有助于我继续前进。
  • 当然,这是另一种技术。我使用了我从互联网上找到和学到的东西。在 Josuttis“C++ 模板”中找不到(也许我是盲人)。有什么文章或书籍可以学习吗?谢谢
  • 我主要从博客(尤其是 Eli Bendersky)和en.cppreference.com 中学习。另请参阅:stackoverflow.com/help/someone-answers
猜你喜欢
  • 2013-03-26
  • 1970-01-01
  • 2021-07-10
  • 2013-01-22
  • 1970-01-01
  • 1970-01-01
  • 2019-11-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多