从基对象获取派生类的模板参数

Get template parameter of derived class from base object

提问人:glades 提问时间:4/13/2022 更新时间:4/14/2022 访问量:276

问:

总之:

  • 我有一个没有模板参数的基类和一个有两个参数的派生类。A_baseA
  • 该函数仅接受基类对象foo()
  • foo()应该返回一个对象,该对象与派生类的第一个模板参数 T 具有相同的类型。

这样做的原因是我不想将 foo() 专门用于 A 的所有变体,您可以想象这可能是数百个。

为了在代码中说明这一点,请执行以下操作

#include <cstdlib>

struct A_base
{

};

template <typename T, size_t S>
struct A : A_base
{
    using P = T; // <-- how do I get here from base class A?
    T arr[S];
};


template <typename T>
auto foo(const A_base& ref) -> decltype(/* somehow get P*/)
{
    return /* object of type P */;
}

int main()
{
    A<int, 10> a;

    foo(a);
}

我将另一个参数 P 键入为 T,因为我认为这将使类“拥有”该类型并提供更好的访问。我希望有一个没有虚拟方法的解决方案,因为直到现在我都在使用虚拟通话。

继承 多态性 C++17 using 指令

评论

0赞 Lingxi 4/13/2022
你已经进去了,为什么不直接拿呢?Tfooconst T& ref
0赞 glades 4/13/2022
@Lingxi 用户无需费心指定模板参数。它应该自动推断出来。
0赞 VainMan 4/13/2022
C++ 不是这样工作的。你永远不会通过只给出指向基对象的引用/指针来知道派生类型,除非基类有关于派生类的类型信息,例如它是多态的,并尝试到所有可能的派生类中的每一个,或者它有指示派生类类型的自定义数据成员,那么你可以为所有可能的派生类中的每个编写分支代码。dynamic_cast

答:

0赞 Michaël Roy 4/13/2022 #1

编译器需要在编译时知道 foo() 的返回类型。如果你不能A_base做一个模板,为什么不把foo()本身做一个函数模板呢?

如:

#include <type_traits>

struct A_base{};

template <typename T>
struct B : A_base
{
    static constexpr T val{};
};

template<typename T>
auto foo(const T&)
{
    static_assert(std::is_base_of_v<A_base, T>);  // this works without  
                                                        // depending on a particular
                                                        // constructor
    return T::val;  // for example.
}


struct C {};

int main()
{
    auto x = foo(B<int>{});
    return std::is_same_v<int, decltype(x)>;
}

评论

0赞 glades 4/13/2022
谢谢,但是如果我想自动推断它怎么办?
0赞 Michaël Roy 4/14/2022
@glades 什么意思?在处理模板时,通常的规则始终适用:在编译时必须知道类型。否则,请使用虚拟函数。
0赞 glades 4/14/2022 #2

很抱歉回答我自己的问题,但我发现了一种可能性。我只是创建一个中间虚拟类,其中只有一个继承自 的模板参数 T。然后,我可以使用这个中间类,而不是 参数的基类:A_middleAfoo()

#include <cstdlib>

struct A_base {};

template <typename T>
struct A_middle : A_base { };

template <typename T, size_t S>
struct A : A_middle<T>
{
    T arr[S];
};


template <typename T>
T foo(const A_middle<T>& ref) // deduction works as expected
{
    T var;
    return var;
}

int main()
{
    A<int, 10> b;

    foo(b);
}