如何对特征选定的超类进行子类化?

3

我有一个类的模板(称其为A),它应该是另一个类(B或C)的子类,这取决于我的自定义特质结构体中的编译时条件。我附上了一个能够复现这种行为的片段。

#include <type_traits>

template<typename T>
class cls_template {
public:
  using method_arg_type = T;
  virtual void method(method_arg_type) = 0;
};

using A = cls_template<float>;
using B = cls_template<int>;

template<typename T>
struct traits {
  using cls = std::conditional<std::is_floating_point<T>::value, A, B>;
};

//class C : public traits<float>::cls {
class C : public A {
public:
  virtual void method(method_arg_type arg) {};
};

int main() {
  A *a = new C();
}

如果我像这样留下它(将A作为超类硬编码),一切都正常工作。然而,一旦我用注释掉的一行替换类定义,就会收到以下错误消息:
test.cpp:21:27: error: unknown type name 'method_arg_type'
  virtual void method(method_arg_type arg) {};
                      ^
test.cpp:25:10: error: cannot initialize a variable of type 'A *'
  (aka 'cls_template<float> *') with an rvalue of type 'C *'
  A *a = new C();
     ^   ~~~~~~~

为什么method_arg_type不再被定义了?为什么C不再被识别为A的子类?我发现,如果traits不是一个模板(如果我只是在结构体中硬编码一个类型),那么一切都能正常工作。

1个回答

4
您正在尝试从类型为std::conditional<std::is_floating_point<T>::value, A, B>traits<float>::cls中派生。它既不是A也不是B,而是conditional模板的特化。请从其::type派生,这将按您所期望的方式工作,或者使用conditional_t(C++14)。
class C : public traits<float>::cls::type { // ok
                                   ^^^^^^
public:
  virtual void method(method_arg_type arg) {};
};

demo

template<typename T>
struct traits {
  using cls = std::conditional_t<std::is_floating_point<T>::value, A, B>;
                              ^^
  // above is C++14, in C++11 you'd have to write
  // using cls = typename std::conditional<std::is_floating_point<T>::value, A, B>::type;
};

class C : public traits<float>::cls { // also ok
public:
  virtual void method(method_arg_type arg) {};
};

demo


1
此外,可以使用 using cls = typename std::conditional<std::is_floating_point<T>::value, A, B>::type;,但是 std::conditional_t 看起来更好。+1 - NathanOliver
唉,是的,你在例子中有了类型,但不幸的是这不是我在真实代码中遇到的问题。我会尝试隔离另一个片段。 - wesolyromek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接