是否可以自动推断函数模板的模板参数的基类?

Is it possible to auto-deduce the base class of a function template's template argument?

本文关键字:参数 基类 函数模板 是否      更新时间:2023-10-16

是否可以编写一个模板函数来拥有关于模板参数基类的类型信息?(假设模板参数仅从一个类派生)

所以,我正在寻找这样的东西:

template <class T> 
auto f(T t) -> decltype(...) { // ... is some SFINAE magic that 
                               //     catches B, the base of T
    std::cout << (B)t << std::endl;
}  

编辑:一些相关背景。我正在编写A*算法的通用实现。模板参数是Node结构。因此,用户可以定义:

struct NodeBase {
    REFLECTABLE((double)g, (double)f)
        // Using the REFLECTABLE macro as described here:                    
        // http://stackoverflow.com/a/11744832/2725810 
};
struct NodeData : public NodeBase {
    using Base1 = NodeBase;
    REFLECTABLE((double)F)
};

我想写一个函数来打印节点结构的内容。CCD_ 3完成了提取CCD_。但是,当用户给我一个NodeData实例时,我的函数也需要打印NodeBase组件的内容。稍后我想为两个和三个基类添加函数的重载。

您正在寻找的SFINAE内容通常是不可能的。对于多重继承,您会怎么做?私有/受保护的继承?我敢打赌,还有一些更复杂的问题我还没有想过。我看到的唯一方法是一致地使用一些反射库(而不仅仅是一个宏),在其中您可以显式地定义想要获得的结果。

相反,您可能正在寻找的非SFINAE和非令人兴奋的方法是简单地为NodeBase重载一次函数,然后通过(const-)引用传递派生类型:

auto f(NodeBase const& t)
{
    std::cout << t << std::endl;
} 

调用f(NodeData{})然后将自动获得对基类NodeBase的引用。请注意,引用在这里很重要,否则您将对派生对象进行切片。

如果您知道类可以从哪些类型继承,这里有一个方法可以为每个实例挖掘出所有实际基类
它遵循一个最小的工作示例:

#include<type_traits>
#include<iostream>
template<int i>
struct check: check<i+1> { };
template<>
struct check<3> { };
struct B1 { };
struct B2 { };
struct B3 { };
struct D: B1, B3 { };
template<class T>
typename std::enable_if<std::is_convertible<T, B1>::value>::type
f(check<0>, T t) {
    B1 b1 = static_cast<B1>(t);
    std::cout << "B1" << std::endl;
    f(check<1>{}, t);
}
template<class T>
typename std::enable_if<std::is_convertible<T, B2>::value>::type
f(check<1>, T t) {
    B2 b2 = static_cast<B2>(t);
    std::cout << "B2" << std::endl;
    f(check<2>{}, t);
}
template<class T>
typename std::enable_if<std::is_convertible<T, B3>::value>::type
f(check<2>, T t) {
    B3 b3 = static_cast<B3>(t);
    std::cout << "B3" << std::endl;
    f(check<3>{}, t);
}
template<class T>
void f(check<3>, T) {
    std::cout << "end" << std::endl;
}
template <class T> 
void f(T t) {
    f(check<0>{}, t);
}
int main() {
    D d;
    f(d);
}

注意它是如何跳过涉及B2的函数的,因为它不是D的基类型
如果您有3个以上的类型要继承,则此方法也很容易扩展,它不强制使用固定的继承链,并且可以对不同的类型执行不同的操作。