我正在尝试使用boost::is_base_of
来检测CRTP基类Generic
是否可以识别其对等项,即T
也来自的类。
如Generic<T>::init()
所示,我想使用这些机制,以便允许类Generic<T>
添加指向其同伴Bar1
或Bar2
的函数的指针(从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
可能会继承Bar1
和Bar3
但不会继承Bar2
,而之前我必须存储指向相应setValue
的指针才能快速访问。 Generic<T>
旨在履行Foo
,X
等
答案 0 :(得分:1)
在我没有中间人的情况下,我无法设想这个工作......
是否可以创建一个用运算符重载封装所需逻辑的结构?该结构将具有一个原始指针,然后您可以使用重载来对其进行处理,以确保它被正确使用。
另一个看似可读的方法是创建另一个前向类,它充当Facade然后利用它。
答案 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;
}