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

时间:2015-12-10 13:50:20

标签: c++ c++11

是否可以编写一个模板函数,该函数具有关于模板参数的基类的类型信息? (假设模板参数仅来自一个类)

所以,我正在寻找这样的事情:

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)
};

我想编写一个打印节点结构内容的函数。 REFLECTABLE完成了提取struct字段的所有艰苦工作。但是,当用户给我一个NodeData实例时,我的函数也需要打印NodeBase组件的内容。我想稍后为两个和三个基类添加我的函数的重载。

2 个答案:

答案 0 :(得分:1)

您正在寻找的SFINAE东西通常是不可能的。你会为多重继承做什么?私有/受保护的继承?而且我敢打赌,我还没有考虑过更复杂的问题。我看到的唯一方法是始终使用一些反射库(而不仅仅是一个宏),您可以在其中明确定义要获取的结果。

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

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

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

答案 1 :(得分:0)

如果你知道你的类可以继承的类型是什么,这里有一个方法来挖掘每个实例的所有实际基类。
它遵循一个最小的工作示例:

#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种类型可以继承,这个方法也很容易扩展,它不会强制使用固定的继承链,你可以对不同的类型执行不同的操作。