gpt4 book ai didi

c++ - 使用子类作为基类的模板参数和嵌套名称说明符

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:44:28 27 4
gpt4 key购买 nike

我将我的类用作其父类之一的模板参数,而该父类在模板参数中使用它(通过 sizeof())。

编译器给我:

error : incomplete type 'Invoker::workerClass {aka MyClass}' used in nested name specifier

但是这个类在文件中定义的很好。我想这是因为子类在基类实例化的那一刻没有被实例化,但是这种事情发生在CRTP上。没有问题。

我在模板参数中使用子类的原因是,如果子类具有或不具有特定函数,则执行不同的函数调用。

这是一个用于测试的最小代码

/* Structure similar to boost's enable if, to use
SFINAE */
template <int X=0, class U = void>
struct test {
typedef U type;
};

enum Commands {
Swim,
Fly
};

/* Structure used for template overloading,
as no partial function template specialization available */
template<Commands T>
struct Param {

};

template <class T>
class Invoker
{
public:
typedef T workerClass;

workerClass *wc() {
return static_cast<workerClass*>(this);
}

template <Commands command>
void invoke() {
invoke2(Param<command>());
}

/* If the child class has those functions, call them */
/* Needs template paramter Y to apply SFINAE */
template<class Y=int>
typename test<sizeof(Y)+sizeof(decltype(&workerClass::fly))>::type
invoke2(Param<Fly>) {
wc()->fly();
}

template<class Y=int>
typename test<sizeof(Y)+sizeof(decltype(&workerClass::swim))>::type
invoke2(Param<Swim>) {
wc()->shoot();
}

template<Commands command>
void invoke2(Param<command>) {
/* Default action */
printf("Default handler for command %d\n", command);
}
};

template <class T, class Inv = Invoker<T> >
class BaseClass : public Inv
{
public:
template<Commands command>
void invoke() {
Inv::template invoke<command>();
}
};

class MyClass : public BaseClass<MyClass>
{
public:
void swim() {
printf("Swimming like a fish!\n");
}

/* void fly(); */
};


void testing() {
MyClass foo;
foo.invoke<Fly>(); /* No 'void fly()' in MyClass, calls the default handler */
foo.invoke<Swim>(); /* Should print the swimming message */
}

错误发生在以下行:

typename test<sizeof(Y)+sizeof(decltype(&workerClass::fly))>::type 

那么,有没有编译器支持这个,或者这个标准明确指定为模板的无效使用?我是否必须改变我这样做的方式并找到解决方法? CRTP 让我希望代码可能有效,但我不确定。

如果这真的不可能,那么究竟为什么,为什么 CRTP 可以工作?

最佳答案

正如 ildjarn 指出的那样,解决方案是添加另一个间接级别。

这是通过将测试函数更改为接受类型来完成的:

template <typename X, class U = void>
struct test {
typedef U type;
};

然后将子类作为模板参数传递,而不是从一开始就指定它:

    template<class Y=workerClass>
typename test<decltype(&Y::fly)>::type
invoke2(Param<Fly>) {
wc()->fly();
}

template<class Y=workerClass>
typename test<decltype(&Y::swim)>::type
invoke2(Param<Swim>) {
wc()->swim();
}

这样,嵌套说明符仅在函数被调用时才被评估,而不是在类评估时评估,到那时子类已经被评估。加上传递默认模板参数的可能性,我们可以在没有任何模板参数的情况下调用该函数。

模板现在也更具可读性。示例代码现在工作正常:

class MyClass : public BaseClass<MyClass>
{
public:
void swim() {
printf("Swimming like a fish!\n");
}

/* void fly(); */
};


void testing() {
MyClass foo;
foo.invoke<Fly>(); /* No 'void fly()' in MyClass, calls the default handler */
foo.invoke<Swim>(); /* Should print the swimming message */
}

关于c++ - 使用子类作为基类的模板参数和嵌套名称说明符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7313642/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com