使用增强单位:是否可以为复合材料类型制作无量纲的模型

时间:2018-03-16 12:58:08

标签: c++ templates boost boost-units

我们希望将boost ::单位用于强类型,但也需要使用无量纲类型来实现兼容性,例如与其他图书馆。 有没有办法以通用的方式实现它? 以下代码的内容 (显然不编译)

#include <boost/units/systems/si.hpp>
using namespace boost::units;
using SiTime = quantity<boost::units::si::time, double>;
using SiLength = quantity<boost::units::si::length, double>;

template<typename TIME,typename LENGTH>
struct Kernel{
    using   time_t                =  TIME;
    using   length_t              =  LENGTH;    
};
using KernelD = Kernel<double,double>;
using KernelSi = Kernel<SiTime,SiLength>;

template<typename TO_KERNEL>
struct composite_cast{
    template<template <typename> class COMPOSITE,typename FROM_KERNEL>
    COMPOSITE<TO_KERNEL> operator()(COMPOSITE<FROM_KERNEL> value){         
        (void)value;
        //how could this work ?
        return COMPOSITE<TO_KERNEL>();
    }  
};

template<typename KERNEL>
struct Foo{
    typename KERNEL::length_t length;
    typename KERNEL::time_t time;
};   
using FooSi = Foo<KernelSi>;
using FooD = Foo<KernelD>;

template<typename KERNEL>
struct Bar{
    Foo<KERNEL> a;
    Foo<KERNEL> b;    
};   
using BarSi = Bar<KernelSi>;
using BarD = Bar<KernelD>;

int main(int, char**) {
    FooSi fooSi;
    FooD fooD =  composite_cast<KernelD>(fooSi);
    BarSi barSi;
    BarD barD =  composite_cast<KernelD>(barSi);    
    return 0;
}

1 个答案:

答案 0 :(得分:1)

除了示例代码中的一连串语法错误之外,此代码不起作用,因为COMPOSITE需要是模板 - 模板参数类型

template <typename TO_KERNEL> struct composite_cast {
    template <template <typename> class COMPOSITE, typename FROM_KERNEL>
    COMPOSITE<TO_KERNEL> operator()(COMPOSITE<FROM_KERNEL> value) {
        // how could this work ?
        return {};
    }
};

那就是说,我会在这里进行明确的转换:

<强> Live On Coliru

#include <boost/units/systems/si.hpp>
using namespace boost::units;
using SiTime = quantity<boost::units::si::time, double>;
using SiLength = quantity<boost::units::si::length, double>;

template <typename TIME, typename LENGTH> struct Kernel {
    using time_t = TIME;
    using length_t = LENGTH;
};

using KernelD  = Kernel<double, double>;
using KernelSi = Kernel<SiTime, SiLength>;

template <typename KERNEL> struct Foo {
    typename KERNEL::length_t length;
    typename KERNEL::time_t time;

    template <typename K2> explicit operator Foo<K2>() const { return { 
        quantity_cast<typename K2::length_t>(length),
        quantity_cast<typename K2::time_t>(time) };
    }
};

using FooSi = Foo<KernelSi>;
using FooD = Foo<KernelD>;

template <typename KERNEL> struct Bar {
    Foo<KERNEL> a;
    Foo<KERNEL> b;

    template <typename K2> explicit operator Bar<K2>() const { 
        return { static_cast<Foo<K2>>(a), static_cast<Foo<K2>>(b) };
    }
};

using BarSi = Bar<KernelSi>;
using BarD = Bar<KernelD>;

int main() {
    FooSi fooSi;
    FooD fooD = static_cast<FooD>(fooSi);
    BarSi barSi;
    BarD barD = static_cast<BarD>(barSi);
}

显式转换函数

如果您不想拥有成员运营商,请将其免费:

<强> Live On Coliru

#include <boost/units/systems/si.hpp>
using namespace boost::units;
using SiTime = quantity<boost::units::si::time, double>;
using SiLength = quantity<boost::units::si::length, double>;

template <typename TIME, typename LENGTH> struct Kernel {
    using time_t = TIME;
    using length_t = LENGTH;
};

using KernelD  = Kernel<double, double>;
using KernelSi = Kernel<SiTime, SiLength>;

template <typename KERNEL> struct Foo {
    typename KERNEL::length_t length;
    typename KERNEL::time_t time;
};

using FooSi = Foo<KernelSi>;
using FooD = Foo<KernelD>;

template <typename KERNEL> struct Bar {
    Foo<KERNEL> a;
    Foo<KERNEL> b;
};

template <typename K2, typename K1>
Foo<K2> kernel_cast(Foo<K1> const& foo) {
    return { 
        quantity_cast<typename K2::length_t>(foo.length),
        quantity_cast<typename K2::time_t>(foo.time) 
    };
}

template <typename K2, typename K1>
Bar<K2> kernel_cast(Bar<K1> const& bar) {
    return { kernel_cast<K2>(bar.a), kernel_cast<K2>(bar.b) };
}

using BarSi = Bar<KernelSi>;
using BarD = Bar<KernelD>;

int main() {
    FooSi fooSi;
    FooD fooD = kernel_cast<KernelD>(fooSi);
    BarSi barSi;
    BarD barD = kernel_cast<KernelD>(barSi);
}

有你的蛋糕并且吃它

顺便提一下,自由函数方法与原始composite_cast函数对象非常吻合:

template <typename TO_KERNEL> struct composite_cast {
    template <template <typename> class COMPOSITE, typename FROM_KERNEL>
    COMPOSITE<TO_KERNEL> operator()(COMPOSITE<FROM_KERNEL> const& value) const {
        return kernel_cast<TO_KERNEL>(value);
    }
};

int main() {
    composite_cast<KernelD> caster;

    FooSi fooSi;
    FooD fooD = caster(fooSi);
    BarSi barSi;
    BarD barD = caster(barSi);
}