遵循'Modern C ++ Design'的技术,我正在实现一个具有各种编译时优化的持久性库。如果该变量派生自给定的类,我希望能够将函数调度到模板化成员变量:
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 = double,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继承,则编译器会发出一组代码,如果不继承,则编译器会发出另一组代码。
有什么建议吗?
答案 0 :(得分:3)
重载对于实现编译时调度非常有用,正如 Alexandrescu 在他的“Modern C ++ Design”一书中提出的那样。
您可以使用这样的类在编译时将布尔值或整数转换为类型:
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()或更好的实现作为元函数
答案 1 :(得分: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_);
}
答案 2 :(得分:1)
提升特质有:is_base_of
答案 3 :(得分:0)
查看boost模板元编程库。此外,根据您要完成的任务,请查看boost序列化库,因为它可能已经拥有您需要的内容。
答案 4 :(得分:0)
我有兴趣将这个'从第一原则'作为一种教育好奇心。但是,我会看一下Boost库。
无论如何,我认为is_base_of没有任何帮助 - 它与SUPERSUBCLASS宏完全相同......
答案 5 :(得分: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)