1

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

如中所示Generic<T>::init(),我想使用这些机制来允许类Generic<T>将指针添加到其对等函数之一Bar1Bar2T也从中派生)映射。不幸的是,无法检测到不派生自的boost::is_base_of类,例如。Bar3T

#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>旨在为 等 履行这个Foo角色X

4

2 回答 2

1

在我的脑海中,我无法想象没有中间人的工作......

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

另一种看似易读的方法是创建另一个作为 Facade 的前向类,然后利用它。

这类似于需要覆盖逆变换方法

于 2012-05-16T13:21:53.953 回答
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;
}
于 2012-05-16T13:39:18.993 回答