3

我正在尝试使用如下所示的简单示例中的静态多态性。

#include <iostream>

template <typename Derived>
struct Base
{
    decltype(auto) foo() { return static_cast<Derived&>(*this).foo(); }
};

struct Derived : Base<Derived>
{
    void foo() { std::cout << "Derived" << std::endl; }
};

template <typename T>
struct Traits;

template <typename T>
struct Traits<Base<T>>
{
    using Derived = T;
};


template <typename T>
struct Object
{
    template <typename U>
    Object(U&& data) : m_data(std::forward<U>(data)) {}

    T m_data;
};

template <typename T>
decltype(auto) polymorphicCall(T&& obj)
{
    using Derived = typename Traits<std::decay_t<T>>::Derived; 
    return Object<Derived>(static_cast<Derived&>(obj));
}

int main()
{
    Derived d;
    polymorphicCall(d);

    return 0;
}

问题是TinpolymorphicCall被推断为Derived,这样任何东西都可以传递给该函数,甚至int。有没有办法只接受Base<Derived>类型?

我尝试使用转发引用和enable_ifon 模板参数,但是我无法推断出Bases 模板参数。

有什么方法可以同时使用转发引用和静态多态性?

编辑:更新了代码示例以包含实际的转发参考以及如何尝试使用它。

显示的错误是:“错误:不完整类型'struct Traits'的无效使用”

链接:https ://godbolt.org/z/3EcS47

4

2 回答 2

2

如果目标只是限制使用polymorphicCall派生自Base您的类型,则可以使用 astatic_assert和类型特征来做到这一点。

#include <iostream>

template <typename Derived>
struct Base
{
    decltype(auto) foo() { return static_cast<Derived&>(*this).foo(); }
};

struct Derived : Base<Derived>
{
    void foo() { std::cout << "Derived" << std::endl; }
};

template <typename T, typename = void>
struct IsDerivedFromBase : std::false_type {};

template <typename T>
struct IsDerivedFromBase<T, std::enable_if_t<std::is_base_of_v<Base<T>, T>>> : std::true_type {};


template <typename T>
struct Object
{
    template <typename U>
    Object(U&& data) : m_data(std::forward<U>(data)) {}

    T m_data;
};

template <typename T>
decltype(auto) polymorphicCall(T&& obj)
{
    using Derived = std::remove_cvref_t<T>;
    static_assert(IsDerivedFromBase<Derived>::value);
    return Object<Derived>(std::forward<T>(obj));
}

int main()
{
    Derived d;
    polymorphicCall(d);
    int i;
    //polymorphicCall(i);

    return 0;
}
于 2020-03-09T12:31:19.067 回答
0

我不确定您需要在示例中的哪个位置知道Derived类型,但您可以制作类型特征,以便Derived为每个Base实例化提供:

template <typename>
struct derived_of;

template <typename Derived>
struct derived_of<Base<Derived>>
{
    using type = Derived;
};

并将其与腐烂的类型一起使用。

于 2020-03-09T11:43:01.010 回答