为一组模板参数重载方法的递归继承
recursive inheritance for overloading a method for a set of template arguments
我需要找到一种方法在给定一组模板参数的情况下递归构建 class,以便 class 从自身继承并为当前第一个构建方法 f
模板参数列表中的模板参数,然后通过传递列表的其余部分从自身继承。
所以,基本上我想为 class C
实现以下接口:
C<T1, T2, T3> c;
c
现在有方法 C::f(T1)
、C::f(T2)
和 C::f(T3)
到目前为止我的方法是这样的:
// primary template
template <class H, class...>
class C {};
// base case where class... is empty
template <class H, class...>
class C<H>
{
public:
void f(const H& h){
// std::cout << typeid(h).name() << "\n";
}
};
// recursive case where T is nonempty
template <class H, class... T>
class C : public C<T...>
{
public:
void f(const H& h){
// std::cout << typeid(h).name() << "\n";
}
};
这实际上并没有编译,因为我得到
error: redefinition of 'C' class C : public C
我的方法是否基本上可行,只是语义和/或语法无效代码的问题,还是这种方法原则上不起作用?
首先,class 不能从自身继承。
其次,您显然想要完成的是让每个模板参数生成一个 class 方法,该方法将 class 作为参数。
在这种情况下,像这样的东西应该可以工作。
template<typename ...> class C;
template<>
class C<> {};
template<typename T, typename ...Args>
class C<T, Args...> : public C<Args...> {
public:
void f (const T &)
{
// Whatever...
}
};
请注意,这不是 class 从自身继承。它是一个继承自另一个模板实例的模板实例。每个模板实例都是唯一的 class.
请注意,您对此处讨论的 class 方法只有一个定义,而不是您尝试定义的两个。这是一个小改进。
另一个改进是考虑以这种方式重新排列 class 层次结构,前提是考虑到您的其他 class 要求:
template<typename T> class F {
public:
void f (const T &)
{
}
};
template<typename ...> class C;
template<>
class C<> {};
template<typename T, typename ...Args>
class C<T, Args...> : public C<Args...> , public F<T> {
};
使用这种方法,无论您使用 C<int, float>
还是 C<int, char *>
,class 方法将始终被声明为 F<int>
的方法。这会稍微减少生成的代码浮点数,因为任何包含 int
的 C
实例都会生成一个 class 方法实例,而不是两个单独的方法,例如 C<int, float>::f(const int &)
和 C<int, char *>::f(const int &)
,否则它们将完全相同。
作为替代方法,我提出了一种基于混入的解决方案。请随意忽略 class type_name
引入的样板文件,其目的是向您展示正确的 部分 是在每个参数基础上选取的。
它遵循一个最小的工作示例:
#include<type_traits>
#include<utility>
#include<iostream>
template<typename> struct type_name;
template<> struct type_name<int> { static const char *name; };
template<> struct type_name<double> { static const char *name; };
template<> struct type_name<char> { static const char *name; };
const char * type_name<int>::name = "int";
const char * type_name<double>::name = "double";
const char * type_name<char>::name = "char";
template<typename T>
struct Part {
void func(T t) {
std::cout << type_name<T>::name << ": " << t << std::endl;
}
};
template<typename... T>
struct S: private Part<T>... {
template<typename... Args>
void f(Args&&... args) {
using acc_t = int[];
acc_t acc = { 0, (Part<std::decay_t<Args>>::func(std::forward<Args>(args)), 0)... };
(void)acc;
}
};
int main() {
S<int, double, char> s;
s.f(42);
s.f(0.1);
s.f('c');
s.f('a', 0.3, 23);
}
此方法的一些优点:
Part<T>
对任何 T
只定义一次,无论你在不同的包中使用它多少次。
S<T, T>
在 compile-time 时被拒绝,更普遍的是所有那些包含相同类型两次或更多次的包。否则他们会产生 f(T)
的多个定义,随后的调用可能会模棱两可。
您可以根据要求使用单个参数调用 f
。无论如何,如示例所示,您可以使用 N
参数调用 f
,该调用等效于使用单个参数 N
调用 f
。
换句话说,你可以使用这个:
s.f('a', 0.3, 23);
或者这样:
s.f('a');
s.f(0.3);
s.f(23);
两种情况下的结果是一样的。
如果需要,可以通过如下定义 S
轻松关闭此功能:
template<typename... T>
struct S: private Part<T>... {
template<typename U>
void f(U &&u) {
Part<std::decay_t<U>>::func(std::forward<U>(u));
}
};
在 wandbox 上查看 运行。
附带说明一下,这是在 C++14 中模拟折叠表达式的常用技巧:
template<typename... Args>
void f(Args&&... args) {
using acc_t = int[];
acc_t acc = { 0, (Part<std::decay_t<Args>>::func(std::forward<Args>(args)), 0)... };
(void)acc;
}
您可以在 SO 和网络上找到更多相关信息。
我需要找到一种方法在给定一组模板参数的情况下递归构建 class,以便 class 从自身继承并为当前第一个构建方法 f
模板参数列表中的模板参数,然后通过传递列表的其余部分从自身继承。
所以,基本上我想为 class C
实现以下接口:
C<T1, T2, T3> c;
c
现在有方法 C::f(T1)
、C::f(T2)
和 C::f(T3)
到目前为止我的方法是这样的:
// primary template
template <class H, class...>
class C {};
// base case where class... is empty
template <class H, class...>
class C<H>
{
public:
void f(const H& h){
// std::cout << typeid(h).name() << "\n";
}
};
// recursive case where T is nonempty
template <class H, class... T>
class C : public C<T...>
{
public:
void f(const H& h){
// std::cout << typeid(h).name() << "\n";
}
};
这实际上并没有编译,因为我得到
error: redefinition of 'C' class C : public C
我的方法是否基本上可行,只是语义和/或语法无效代码的问题,还是这种方法原则上不起作用?
首先,class 不能从自身继承。
其次,您显然想要完成的是让每个模板参数生成一个 class 方法,该方法将 class 作为参数。
在这种情况下,像这样的东西应该可以工作。
template<typename ...> class C;
template<>
class C<> {};
template<typename T, typename ...Args>
class C<T, Args...> : public C<Args...> {
public:
void f (const T &)
{
// Whatever...
}
};
请注意,这不是 class 从自身继承。它是一个继承自另一个模板实例的模板实例。每个模板实例都是唯一的 class.
请注意,您对此处讨论的 class 方法只有一个定义,而不是您尝试定义的两个。这是一个小改进。
另一个改进是考虑以这种方式重新排列 class 层次结构,前提是考虑到您的其他 class 要求:
template<typename T> class F {
public:
void f (const T &)
{
}
};
template<typename ...> class C;
template<>
class C<> {};
template<typename T, typename ...Args>
class C<T, Args...> : public C<Args...> , public F<T> {
};
使用这种方法,无论您使用 C<int, float>
还是 C<int, char *>
,class 方法将始终被声明为 F<int>
的方法。这会稍微减少生成的代码浮点数,因为任何包含 int
的 C
实例都会生成一个 class 方法实例,而不是两个单独的方法,例如 C<int, float>::f(const int &)
和 C<int, char *>::f(const int &)
,否则它们将完全相同。
作为替代方法,我提出了一种基于混入的解决方案。请随意忽略 class type_name
引入的样板文件,其目的是向您展示正确的 部分 是在每个参数基础上选取的。
它遵循一个最小的工作示例:
#include<type_traits>
#include<utility>
#include<iostream>
template<typename> struct type_name;
template<> struct type_name<int> { static const char *name; };
template<> struct type_name<double> { static const char *name; };
template<> struct type_name<char> { static const char *name; };
const char * type_name<int>::name = "int";
const char * type_name<double>::name = "double";
const char * type_name<char>::name = "char";
template<typename T>
struct Part {
void func(T t) {
std::cout << type_name<T>::name << ": " << t << std::endl;
}
};
template<typename... T>
struct S: private Part<T>... {
template<typename... Args>
void f(Args&&... args) {
using acc_t = int[];
acc_t acc = { 0, (Part<std::decay_t<Args>>::func(std::forward<Args>(args)), 0)... };
(void)acc;
}
};
int main() {
S<int, double, char> s;
s.f(42);
s.f(0.1);
s.f('c');
s.f('a', 0.3, 23);
}
此方法的一些优点:
Part<T>
对任何T
只定义一次,无论你在不同的包中使用它多少次。S<T, T>
在 compile-time 时被拒绝,更普遍的是所有那些包含相同类型两次或更多次的包。否则他们会产生f(T)
的多个定义,随后的调用可能会模棱两可。您可以根据要求使用单个参数调用
f
。无论如何,如示例所示,您可以使用N
参数调用f
,该调用等效于使用单个参数N
调用f
。
换句话说,你可以使用这个:s.f('a', 0.3, 23);
或者这样:
s.f('a'); s.f(0.3); s.f(23);
两种情况下的结果是一样的。
如果需要,可以通过如下定义S
轻松关闭此功能:template<typename... T> struct S: private Part<T>... { template<typename U> void f(U &&u) { Part<std::decay_t<U>>::func(std::forward<U>(u)); } };
在 wandbox 上查看 运行。
附带说明一下,这是在 C++14 中模拟折叠表达式的常用技巧:
template<typename... Args>
void f(Args&&... args) {
using acc_t = int[];
acc_t acc = { 0, (Part<std::decay_t<Args>>::func(std::forward<Args>(args)), 0)... };
(void)acc;
}
您可以在 SO 和网络上找到更多相关信息。