最近,我遇到一个问题,我能想到的唯一解决方案是使用宏,尽管出于某些目的,我认为这是一个丑陋的解决方案。
问题在于,当声明一个类时,随着添加更多代码并需要新功能,其模板参数始终会更改。
我意识到,如果类中的模板数量不断变化,这可能意味着代码设计不能很好地完成,但是即使如此,我也想知道是否有解决方案。
这是Test.hpp中的代码示例,该类的声明和所有方法的原型。
template<typename A,
typename B,
typename C>
struct Test
{
void do_something_1();
void do_something_2();
void do_something_3();
}
在Test.cpp中,我们将像这样实现所有方法
template<typename A,
typename B,
typename C>
Test<A,B,C>::do_something_1() { /* ... */ }
template<typename A,
typename B,
typename C>
Test<A,B,C>::do_something_2() { /* ... */ }
template<typename A,
typename B,
typename C>
Test<A,B,C>::do_something_3() { /* ... */ }
您会看到我们重复了很多模板部分,如果我们要添加typename D
来执行该类,则必须在所有Test.cpp方法中对其进行更改,因此使用宏我们可以在宏中定义所有宏并使用它,但是阅读代码的人可能不了解那里到底发生了什么或宏看起来如何扩展。
也可以使用typename... Args
来获取它们,然后以某种方式在类中对其进行处理,但这非常笨拙,因为从Args中获取Nth类型不是一件容易的事,并且没有提供最终用户应使用多少种类型,以及除文档内部以外应使用的顺序,如果我们想将模板参数分为两类,请说一类用于存储哪种类型,一类用于转换为类以某种方式处理类型,有两个typename... Args
,没有简单的方法可以说出第一个结束的位置和第二个开始的位置。
我唯一想到的方法是添加一个打包结构(即类型的结构),并按如下方式使用它:
在Test.hpp中
template<typename A_,
typename B_,
typename C_>
struct packed_struct
{
using A = A_;
using B = B_;
using C = C_;
};
template<typename packed_struct_type>
struct Test
{
using A = typename packed_struct_type::A;
using B = typename packed_struct_type::B;
using C = typename packed_struct_type::C;
void do_something_1();
void do_something_2();
void do_something_3();
};
在Test.cpp中,我们只声明一个类型名称,packed_struct_type,我们还可以随时轻松地添加一个参数,这感觉是最好的解决方案,因为这样我们可以强制执行应该有多少个模板参数,并且每个名称,以便用户不能混淆它们。
使用proposal N3728和proposal N1603可以声明一个typename... Args
,用户可以使用Test< <int, char, double> >
实例化它,并且可以更轻松地检索每种类型,但是它们并不是批准。
当然,最好的方法可能是对打包结构提供一流的语言支持,我们可以使用它们代替typename
来执行该打包,实际上proposal N3728对{{1}的作用}语法,但使用<int, char, double>
而不是packed_struct Args
可以轻松检索具有其名称的每种类型,而不用猜测哪种类型是第一种和第二种,并且用户也可能混淆声明中的类型。但是我找不到针对此特定功能的任何建议,因此,我想实现这一目标的最佳方法是使用上面提供的packed_struct解决方案。
是否有针对此问题的更好的解决方案,或者提供了计划用于c ++ 2a(或更晚但尚未被拒绝)的解决方案的提案?