使用一组基于模板参数的函数重载构建可变参数模板 class?
Building a variadic template class with a set of function overloads based on the template arguments?
动机:我需要为 C++17 库构建一个基础 class,该库将根据用户识别的类型重载虚函数在编译时。基本上,当在基础 class 上调用函数的特定重载时,我想确保在派生 class 中调用正确的版本。我最初的直觉是构建一个虚拟模板函数,但 C++ 当然不允许这样做,因为编译器不知道将它的哪个版本放入虚拟函数 table。因为我会在编译时知道所有类型,但是,是否可以使基 class 本身成为可变参数模板并使用模板参数来构建所需的虚函数的重载版本集?
折叠表达式已经过时了,因为它们不能用于声明函数。递归模板似乎很有前途,但我担心基 class 的长链继承会影响性能。这是我的工作代码:
template <typename... Ts> class MyClass;
template <typename T, typename... Ts>
struct MyClass<T, Ts...> : public MyClass<Ts...> {
using MyClass<Ts...>::MyFunction;
virtual bool MyFunction(T in) { return true; }
};
template <>
struct MyClass<> {
virtual bool MyFunction(...) { return false; }
};
这种技术应该足够了吗?或者有人对我如何实现这个目标有其他想法吗?
我的其他想法包括:
限制可以处理的模板参数的数量,并根据参数列表是否足够长来包含每个重载来启用-if。缺点:这种技术会任意限制类型的数量。
使用可变参数宏构建 class。缺点:这种技术会令人困惑和不优雅。
创建一个函数,将类型分配给基数 class 中的 ID 号,将其作为带有其 ID 的 void *
传递给派生的 class ,并在此时将其翻译回来以进行适当的重载调用。缺点:这种技术很难保证类型安全并尽量减少最终用户需要做的工作量。
现在我倾向于实施这些备选方案中的第一个,并进行一些性能测试以将其与我的工作版本进行比较,但如果我遗漏了一些更清洁的东西,我会很高兴。
您的实现适用于 C++14。
C++17 允许可变参数 using
,以避免递归:
template <typename T>
struct MyClassImpl
{
virtual ~MyClassImpl() = default;
virtual bool MyFunction(T in) = 0; // or { return true; }
};
template <typename... Ts>
struct MyClass : public MyClassImpl<Ts>...
{
using MyClassImpl<Ts>::MyFunction...;
};
动机:我需要为 C++17 库构建一个基础 class,该库将根据用户识别的类型重载虚函数在编译时。基本上,当在基础 class 上调用函数的特定重载时,我想确保在派生 class 中调用正确的版本。我最初的直觉是构建一个虚拟模板函数,但 C++ 当然不允许这样做,因为编译器不知道将它的哪个版本放入虚拟函数 table。因为我会在编译时知道所有类型,但是,是否可以使基 class 本身成为可变参数模板并使用模板参数来构建所需的虚函数的重载版本集?
折叠表达式已经过时了,因为它们不能用于声明函数。递归模板似乎很有前途,但我担心基 class 的长链继承会影响性能。这是我的工作代码:
template <typename... Ts> class MyClass;
template <typename T, typename... Ts>
struct MyClass<T, Ts...> : public MyClass<Ts...> {
using MyClass<Ts...>::MyFunction;
virtual bool MyFunction(T in) { return true; }
};
template <>
struct MyClass<> {
virtual bool MyFunction(...) { return false; }
};
这种技术应该足够了吗?或者有人对我如何实现这个目标有其他想法吗?
我的其他想法包括:
限制可以处理的模板参数的数量,并根据参数列表是否足够长来包含每个重载来启用-if。缺点:这种技术会任意限制类型的数量。
使用可变参数宏构建 class。缺点:这种技术会令人困惑和不优雅。
创建一个函数,将类型分配给基数 class 中的 ID 号,将其作为带有其 ID 的
void *
传递给派生的 class ,并在此时将其翻译回来以进行适当的重载调用。缺点:这种技术很难保证类型安全并尽量减少最终用户需要做的工作量。
现在我倾向于实施这些备选方案中的第一个,并进行一些性能测试以将其与我的工作版本进行比较,但如果我遗漏了一些更清洁的东西,我会很高兴。
您的实现适用于 C++14。
C++17 允许可变参数 using
,以避免递归:
template <typename T>
struct MyClassImpl
{
virtual ~MyClassImpl() = default;
virtual bool MyFunction(T in) = 0; // or { return true; }
};
template <typename... Ts>
struct MyClass : public MyClassImpl<Ts>...
{
using MyClassImpl<Ts>::MyFunction...;
};