1

I am trying to use boost::is_base_of in order to detect if a CRTP base class Generic can identify its peers i.e. classes that T is also derived from.

As shown in Generic<T>::init(), I would like to use these mechanisms in order to allow the class Generic<T> add pointers to functions one of its peers Bar1 or Bar2 (from which T also derives) to a map. Unfortunately boost::is_base_of is unable to detect classes, such as Bar3, that T does not derive from.

#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 error message:

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

Edit

To provide some context for this question. I'm trying to store pointers to the setValue methods of the base classes of each Foo<T> in a map for quick access. The choice of setValue to call depends on a string, thus the map. Another class X may inherit Bar1 and Bar3 but not Bar2, and as before I would have to store pointers to the appropriate setValue's for quick access. Generic<T> aims to fulfil this role for Foo, X etc.

4

2 に答える 2

1

頭のてっぺんから、仲介者なしでこれが機能することを想像することはできません...

演算子のオーバーロードを使用して目的のロジックをカプセル化する構造体を作成することは可能ですか? 構造体には生のポインターがあり、オーバーロードでそれを参照して、正しく使用されていることを確認できます。

別の一見読みやすい方法は、ファサードとして機能する別の前向きのクラスを作成し、それを利用することです。

これは、必要な反分散回避策のオーバーライドに似ています

于 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 に答える