检测CRTP基类的兄弟姐妹

时间:2012-05-16 13:17:01

标签: c++ inheritance stl sfinae crtp

我正在尝试使用boost::is_base_of来检测CRTP基类Generic是否可以识别其对等项,即T也来自的类。

Generic<T>::init()所示,我想使用这些机制,以便允许类Generic<T>添加指向其同伴Bar1Bar2的函数的指针(从T也可以派生出来)到地图。很遗憾,boost::is_base_of无法检测到Bar3未派生的类T

#include <iostream>
#include <cstdlib>
#include <string>
#include <typeinfo>
#include <map>
#include <boost/type_traits.hpp>

//////////////////////////////////////////////////////////////////////////////////////

template<typename T>
class Bar
{
public:
    void setValue()
    {
        std::cout << typeid(this).name() << std::endl;
    }
};

class Bar1 : public Bar<char>{};
class Bar2 : public Bar<bool>{};
class Bar3 : public Bar<long>{};

//////////////////////////////////////////////////////////////////////////////////////

template<typename T>
class Generic
{
public:
    typedef void (T::*setter)();
    void init();
};

template<typename T>
void Generic<T>::init()
{
    std::map<std::string , Generic<T>::setter> setterMap;
    if( boost::is_base_of<Bar1, T >::value ) setterMap["bar1"] = &Bar1::setValue;
    if( boost::is_base_of<Bar2, T >::value ) setterMap["bar2"] = &Bar2::setValue;
    if( boost::is_base_of<Bar3, T >::value ) setterMap["bar3"] = &Bar3::setValue;
    std::cout << setterMap.size() << std::endl;
}

//////////////////////////////////////////////////////////////////////////////////////

template<typename T>
class Foo : public Bar1 , public Bar2 , public Generic<Foo<T> >
{
public:

};

//////////////////////////////////////////////////////////////////////////////////////

int main()
{
    Foo<int> f;
    f.init();

    return EXIT_SUCCESS;
}

//////////////////////////////////////////////////////////////////////////////////////

gcc错误消息:

In static member function ‘static void Generic<T>::init() [with T = Foo<int>]’:
error: cannot convert ‘void (Bar<long int>::*)()’ to ‘void (Foo<int>::*)()’ in assignment

修改

为此问题提供一些背景信息。我正在尝试在地图中存储指向每个setValue基类的Foo<T>方法的指针,以便快速访问。调用setValue的选择取决于字符串,即地图。另一个班级X可能会继承Bar1Bar3但不会继承Bar2,而之前我必须存储指向相应setValue的指针才能快速访问。 Generic<T>旨在履行FooX

的角色

2 个答案:

答案 0 :(得分:1)

在我没有中间人的情况下,我无法设想这个工作......

是否可以创建一个用运算符重载封装所需逻辑的结构?该结构将具有一个原始指针,然后您可以使用重载来对其进行处理,以确保它被正确使用。

另一个看似可读的方法是创建另一个前向类,它充当Facade然后利用它。

这类似于Override contra-variance workaround needed

答案 1 :(得分:1)

杰伊是对的。我做了以下更改,这似乎有效。

template <bool, typename T> struct AddSetter;

template <typename T> struct AddSetter <true, T>
{
    template<typename F>
    void Set (std::map<std::string , typename Generic<T>::setter>& setterMap, const std::string& key, F fn)
    {
        setterMap[key] = fn;
    }
};

template <typename T> struct AddSetter <false, T>
{
    template<typename F>
    void Set (std::map<std::string , typename Generic<T>::setter>& setterMap, const std::string& key, F fn)
    {
    }
};

template<typename T>
void Generic<T>::init()
{
    std::map<std::string , Generic<T>::setter> setterMap;
    AddSetter<boost::is_base_of<Bar1, T >::value, T>().Set (setterMap, "bar1", &Bar1::setValue);
    AddSetter<boost::is_base_of<Bar2, T >::value, T>().Set (setterMap, "bar2", &Bar2::setValue);
    AddSetter<boost::is_base_of<Bar3, T >::value, T>().Set (setterMap, "bar3", &Bar3::setValue);
    std::cout << setterMap.size() << std::endl;
}