使用子类作为基类的模板参数和嵌套名称说明符
Using child class as a template parameter of a base class and as a nested name specifier
我使用我的类作为父类之一的模板形参,并且父类在模板参数中使用它(尽管sizeof())。
编译器给了我:
错误:在嵌套名称说明符中使用了不完整类型'Invoker::workerClass {aka MyClass}'
但是类在文件中定义得很好。我猜这是因为子类没有在基类实例化的时候实例化,然而这种事情发生在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 %dn", 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++
- 如何避免嵌套模板中的模板参数重复
- 重构模板类,该类将其嵌套类用作另一个类的模板参数
- 以嵌套类为参数的友元模板声明
- 是否可以指定 C++20 个模板化 lambda 来推断嵌套在参数中的类型?
- 通过具有嵌套类的工厂类获取多个变异类模板参数包
- 嵌套模板类的模板类模板模板参数的专业化
- 不能使用嵌套结构中的联合元素作为 scanf() 的参数来存储所需的值
- 修改嵌套 lambda 中捕获的参数:gcc 与 clang?
- 声明嵌套在模板参数中的类型的变量?
- 将参考类型作为嵌套模板结构中的模板参数作为模板参数不起作用
- 模板嵌套类模板类作为与完全专业函数的参数
- C++ 17 可以处理嵌套的可变参数模板吗?
- 带有可变参数的嵌套宏在GCC中编译,但在MSVC中不编译
- 在C++中使用模板类的嵌套类作为模板模板参数
- 如何使用variadic参数包的嵌套模板类
- 如何在variadic模板中采用嵌套参数包
- 传递具有依赖嵌套参数类型的模板模板参数时出错
- 可变参数嵌套循环