如何根据模板函数中的类型构造不同的对象?

mat*_*scy 3 c++ templates variadic-templates parameter-pack

这是我的问题,我有一个基类Base、两个派生类ClassA和仅采用两个参数的ClassB形式Base,以及两个类ClassB0ClassB1ClassB采用三个参数派生而来。我想根据传递给函数的类型创建类实例create,如果类型派生自ClassB,则第一个参数将填充为 10。编译器总是警告没有匹配的构造函数。

#include <iostream>
#include <type_traits>

class Base {};
class ClassA : public Base {
public:
  ClassA(int a, int b) : Base() {
    std::cout << "ClassA: " << a << " " << b << "\n\n";
  }
};

class ClassB : public Base {
public:
  ClassB(int a, int b, int c) : Base() {
    std::cout << "ClassB: " << a << " " << b << " " << c << "\n";
  }
};

class ClassB0 : public ClassB {
public:
  ClassB0(int a, int b, int c) : ClassB(a, b, c) { 
    std::cout << "ClassB0: " << a << " " << b << " " << c << "\n\n";
  }
};
class ClassB1 : public ClassB {
public:
  ClassB1(int a, int b, int c) : ClassB(a, b, c) {
    std::cout << "ClassB1: " << a << " " << b << " " << c << "\n\n";
  }
};

template <typename T, typename ...Args>
T* create(Args&&... args) {
  T* comp = nullptr;

  if (std::is_base_of<ClassB, T>::value) {
    std::cout << "True ";
    comp = new T(10, std::forward<Args>(args)...);
  } else {
    std::cout << "False ";
    comp = new T(std::forward<Args>(args)...);
  }

  return comp;
}

int main() {
  create<ClassA>(1, 2);
  create<ClassB0>(2, 3);
  create<ClassB1>(2, 3);
}
Run Code Online (Sandbox Code Playgroud)

son*_*yao 5

问题是,双方的分支if,并else需要在编译时进行评估,尽管其中一个会在运行时进行评估。

您可以应用constexpr if 语句(C++17 起),其条件必须在编译时已知,并且iforelse分支将被丢弃并且不会在编译时再次评估。

如果值为true,则丢弃statement-false(如果存在),否则丢弃statement-true

template <typename T, typename ...Args>
T* create(Args&&... args) {
  T* comp = nullptr;

  if constexpr (std::is_base_of<ClassB, T>::value) {
  // ^^^^^^^^^
    std::cout << "True ";
    comp = new T(10, std::forward<Args>(args)...);
  } else {
    std::cout << "False ";
    comp = new T(std::forward<Args>(args)...);
  }

  return comp;
}
Run Code Online (Sandbox Code Playgroud)

居住

在 C++17 之前,您可以使用SFINAE应用重载。例如

template <typename T, typename ...Args>
typename std::enable_if<std::is_base_of<ClassB, T>::value, T*>::type
create(Args&&... args) {
  T* comp = nullptr;
  std::cout << "True ";
  comp = new T(10, std::forward<Args>(args)...);
  return comp;
}
template <typename T, typename ...Args>
typename std::enable_if<!std::is_base_of<ClassB, T>::value, T*>::type
create(Args&&... args) {
  T* comp = nullptr;
  std::cout << "False ";
  comp = new T(std::forward<Args>(args)...);
  return comp;
}
Run Code Online (Sandbox Code Playgroud)

居住