2008-09-28 44 views
4

从'现代C++设计'的以下技术,我正在实现一个具有各种编译时优化的持久性库。我想派遣功能,模板化的成员变量的能力,如果该变量从给定的类派生:基于编译时类型的调度

template<class T, template <class> class Manager = DefaultManager> class Data 
{ 
private: 
    T *data_; 

public: 
    void Dispatch() 
    { 
     if(SUPERSUBCLASS(Container, T)) 
     { 
     data_->IKnowThisIsHere(); 
     } 
     else 
     { 
     Manager<T>::SomeGenericFunction(data_); 
     } 
    } 
} 

凡SUPERSUBCLASS是一个编译时宏来确定对象继承。当然,在所有T从Container继承的情况下(或者T是一个内部类型等),这都会失败,因为编译器会正确地抱怨IKnowThisIsHere()不是数据成员,即使这条代码路径永远不会被遵循,如T = int预处理后所示:

private: 
    int *data_; 

public: 
    void Dispatch() 
    { 
     if(false) 
     { 
     data_->IKnowThisIsHere(); 

编译器明显抱怨此代码,即使它永远不会执行。使用的dynamic_cast的建议也不起作用,因为再次类型转换试图在编译时这是不可能的(例如使用T =双,的std :: string):

void Dispatch() 
    { 
     if(false) 
     { 
     dynamic_cast<Container*>(data_)->IKnowThisIsHere(); 

error: cannot dynamic_cast '((const Data<double, DefaultManager>*)this)->Data<double, DefaultManager>::data_' (of type 'double* const') to type 'class Container*' (source is not a pointer to class) 
error: cannot dynamic_cast '((const Data<std::string, DefaultManager>*)this)->Da<sttad::string, DefaultManager>::data_' (of type 'struct std::string* const') to type 'class Container*' (source type is not polymorphic) 

我真的需要模拟(或确实劝说!)如果T从Container继承,则编译器发出一组代码;如果不从Container继承,则编译器发出一组代码。

有什么建议吗?

回答

3

超载可能是有用的实施编译时DIS:;运行时调用))编译器,如果你在非多晶型或类类型传递,以类似的方式来之前抱怨正如Alexandrescu在他的书“现代C++设计”中提出的那样。

您可以使用像这样一类在编译时的布尔或整数变换成一个类型:

template <bool n> 
struct int2type 
{ enum { value = n}; }; 

下面的源代码显示了一个可能的应用:

#include <iostream> 

#define MACRO() true // <- macro used to dispatch 

template <bool n> 
struct int2type 
{ enum { value = n }; }; 

void method(int2type<false>) 
{ std::cout << __PRETTY_FUNCTION__ << std::endl; } 

void method(int2type<true>) 
{ std::cout << __PRETTY_FUNCTION__ << std::endl; } 

int 
main(int argc, char *argv[]) 
{ 
    // MACRO() determines which function to call 
    // 

    method(int2type<MACRO()>()); 

    return 0; 
} 

当然什么真的使得工作成为MACRO()或更好的实现作为元功能

+0

感谢长久 - 这正是我之后。 – user23167 2008-09-28 16:07:10

0

查找到升压模板元编程库。另外,根据你正在尝试完成的内容,查看boost序列化库,因为它可能已经有了你所需要的。

0

我有兴趣做这个'从第一原则'作为教育的好奇心。不过,我会看看Boost库。

在任何情况下,我不认为is_base_of是任何帮助 - 它完全一样的SUPERSUBCLASS宏...

0

不幸的是我经历过的太(它是上也是如此,

error: cannot dynamic_cast '((const Data<double, DefaultManager>*)this)->Data<double, RawManager>::data_' (of type 'double* const') to type 'class Container*' (source is not a pointer to class) 

error: cannot dynamic_cast '((const Data<std::string, DefaultRawManager>*)this)->Data<std::string, DefaultManager>::data_' (of type 'struct std::string* const') to type 'class Container*' (source type is not polymorphic) 
2

您需要一种编译时if。然后根据哪种情况调用函数true。这样,编译器就不会偶然发现它无法编译的代码(因为它安全地存储在另一个永远不会实例化的函数模板中)。

实现这种编译时有几种方法if。最常见的是采用SFINAE成语:substitution failure is not an error。 Boost的is_base_of实际上是这个成语的一个实例。要正确使用它,您不会将它写入if表达式中,而是将其用作函数的返回类型。

未经测试的代码:

void Dispatch() 
{ 
    myfunc(data_); 
} 

private: 

// EDIT: disabled the default case where the specialisation matched 
template <typename U> 
typename enable_if_c<is_base_of<Container, U>::value, U>::type myfunc(U& data_) { 
    data_->IKnowThisIsHere(); 
} 

template <typename U> 
typename disable_if_c<is_base_of<Container, U>::value, U>::type myfunc(U& data_) { // default case 
    Manager<U>::SomeGenericFunction(data_); 
} 
+0

该方法将导致模糊的重载。当is_base_of <>元函数成功时,您应该让编译器删除第二个方法(默认情况)。 – 2008-09-28 15:32:56