gpt4 book ai didi

c++ - CRTP接口(interface): different return types in implementation

转载 作者:行者123 更新时间:2023-12-02 10:33:44 29 4
gpt4 key购买 nike

注:
在解释和我的例子中,我使用 eigen图书馆。但是,我的问题可能会被不熟悉该库的人概括和理解,例如通过替换 ConstColXprstd::string_viewVectorstd::string .

问题:
我想使用 CRTP 创建一个接口(interface),其中有两个继承自它的类,它们在调用某些成员函数时有以下不同:

  • 第一个类返回数据成员的 View (Eigen::Matrix<...>::ConstColXpr)
  • 第二个类没有这个数据成员。相反,在调用函数时计算适当的值,然后返回(作为 Eigen::Vector<...> )

  • 两种返回类型具有相同的维度(例如 2x1 列 vector )和相同的接口(interface),即可以以完全相同的方式进行交互。这就是为什么我认为将函数定义为接口(interface)的一部分是合理的。
    但是, 我不知道如何正确定义/限制基类/接口(interface)中的返回类型 . auto编译和执行良好,但没有告诉用户任何期望。

    是否可以以更清晰的方式定义接口(interface)? 我尝试使用 std::invoke_result使用实现函数,但是我必须在接口(interface)之前包含继承类型,这是相当倒退的。而且比 auto好不了多少,因为实际类型仍然需要在实现中查找。

    一个不错的答案是常见的 Eigen类型,其中尺寸清晰。但是,我不希望调用接口(interface)函数需要模板参数(我必须使用 Eigen::MatrixBase ),因为已经有代码取决于接口(interface)。
    另一个不错的答案是允许两种不同返回类型的构造,但不必知道完整的派生类型。但欢迎所有答案和其他反馈!

    这是说明问题的代码:
    #include <Eigen/Dense>
    #include <type_traits>
    #include <utility>
    #include <iostream>

    template<typename T>
    class Base
    {
    public:
    auto myFunc(int) const;

    protected:
    Base();
    };

    template<typename T>
    Base<T>::Base() {
    /* make sure the function is actually implemented, otherwise generate a
    * useful error message */
    static_assert( std::is_member_function_pointer_v<decltype(&T::myFuncImp)> );
    }

    template<typename T>
    auto Base<T>::myFunc(int i) const {
    return static_cast<const T&>(*this).myFuncImp(i);
    }


    using Matrix2Xd = Eigen::Matrix<double,2,Eigen::Dynamic>;

    class Derived1 : public Base<Derived1>
    {
    private:
    Matrix2Xd m_data;

    public:
    Derived1( Matrix2Xd&& );

    private:
    auto myFuncImp(int) const -> Matrix2Xd::ConstColXpr;
    friend Base;
    };

    Derived1::Derived1( Matrix2Xd&& data ) :
    m_data {data}
    {}

    auto Derived1::myFuncImp(int i) const -> Matrix2Xd::ConstColXpr {
    return m_data.col(i);
    }


    class Derived2 : public Base<Derived2>
    {
    private:
    auto myFuncImp(int) const -> Eigen::Vector2d;
    friend Base;
    };

    auto Derived2::myFuncImp(int i) const -> Eigen::Vector2d {
    return Eigen::Vector2d { 2*i, 3*i };
    }

    int main(){
    Matrix2Xd m (2, 3);
    m <<
    0, 2, 4,
    1, 3, 5;

    Derived1 d1 { std::move(m) };

    std::cout << "d1: " << d1.myFunc(2).transpose() << "\n";

    Derived2 d2;

    std::cout << "d2: " << d2.myFunc(2).transpose() << "\n";

    return 0;
    }

    在我的机器上,这打印
    d1: 4 5
    d2: 4 6

    最佳答案

    好的,我想我找到了一个可读性很强的解决方案。仍然欢迎反馈。
    我刚刚定义了另一个模板参数,bool ,它告诉派生类是否保存数据,并使用 std::conditional 定义返回类型那bool :

    #include <Eigen/Dense>
    #include <type_traits>
    #include <utility>
    #include <iostream>


    using Matrix2Xd = Eigen::Matrix<double,2,Eigen::Dynamic>;
    using Eigen::Vector2d;


    template<typename T, bool hasData>
    class Base
    {
    public:
    auto myFunc(int) const ->
    std::conditional_t<hasData, Matrix2Xd::ConstColXpr, Vector2d>;

    protected:
    Base();
    };

    template<typename T, bool hasData>
    Base<T, hasData>::Base() {
    static_assert( std::is_member_function_pointer_v<decltype(&T::myFuncImp)> );
    }

    template<typename T, bool hasData>
    auto Base<T, hasData>::myFunc(int i) const ->
    std::conditional_t<hasData, Matrix2Xd::ConstColXpr, Vector2d> {
    return static_cast<const T&>(*this).myFuncImp(i);
    }



    class Derived1 : public Base<Derived1, true>
    {
    private:
    Matrix2Xd m_data;

    public:
    Derived1( Matrix2Xd&& );

    private:
    auto myFuncImp(int) const -> Matrix2Xd::ConstColXpr;
    friend Base;
    };

    Derived1::Derived1( Matrix2Xd&& data ) :
    m_data {data}
    {}

    auto Derived1::myFuncImp(int i) const -> Matrix2Xd::ConstColXpr {
    return m_data.col(i);
    }


    class Derived2 : public Base<Derived2, false>
    {
    private:
    auto myFuncImp(int) const -> Eigen::Vector2d;
    friend Base;
    };

    auto Derived2::myFuncImp(int i) const -> Eigen::Vector2d {
    return Eigen::Vector2d { 2*i, 3*i };
    }

    int main(){
    Matrix2Xd m (2, 3);
    m <<
    0, 2, 4,
    1, 3, 5;

    Derived1 d1 { std::move(m) };

    std::cout << "d1: " << d1.myFunc(2).transpose() << "\n";

    Derived2 d2;

    std::cout << "d2: " << d2.myFunc(2).transpose() << "\n";

    return 0;
    }

    编译并执行良好。有点冗长,但至少清楚地表明了意图。

    仍然欢迎其他答案。

    关于c++ - CRTP接口(interface): different return types in implementation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61218565/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com