避免专门化模板中的代码重复
Avoiding code duplication in a specialized template
我想有两个类似的模板,一个有1个参数,另一个有2个参数:
template<typename T1, typename T2=void>
struct foo {
T1 m_t1;
T2 m_t2;
foo(T1 t1, T2 t2) : m_t1(t1), m_t2(t2) {}
T1 t1() { return m_t1; }
T2 t2() { return m_t2; }
};
template<typename T1>
struct foo<T1,void> {
T1 m_t1;
foo(T1 t1) : m_t1(t1) {}
T1 t1() { return m_t1; }
};
注意所有与t1相关的东西的代码复制。我怎样才能避免这种情况呢?
唯一的解决方案是在基类中包含尽可能多的代码。例如:
template<typename T1>
struct foo_base {
T1 m_t1;
explicit foo_base(T1 t1) : m_t1(t1) {}
T1 t1() const { return m_t1; }
};
template<typename T1, typename T2=void>
struct foo : foo_base<T1> {
T2 m_t2;
foo(T1 t1, T2 t2) : foo_base<T1>(t1), m_t2(t2) {}
T2 t2() const { return m_t2; }
};
template<typename T1>
struct foo<T1,void> : foo_base<T1> {
explicit foo(T1 t1) : foo_base<T1>(t1) {}
};
这是一个非常普遍的问题。
在这种情况下,您可以将T1
相关的内容放在基类中。一般来说,您应该避免"一二多"问题。您在这里所做的也可以通过std::tuple
实现,它也是Boost库的一部分。
对于它的价值,tuple
通过组成任意数量的基类来工作。
仔细查看您的代码,您正在重新实现std::tuple
。将t1
和t2
方法交换为自由函数std::get<N>
,您将拥有std::tuple
提供的一切(甚至更多)。为方便起见,如果有作为方法,可以这样考虑:
template<typename... Ts>
struct foo {
typedef std::tuple<Ts...> Tup;
Tup m_ts;
foo(Ts... ts) : m_ts{ts...} {} //!
template <unsigned N>
std::tuple_element<N, Tup> t() { return std::get<N>(Tup); }
};
对于//!
:当然,您可以将构造函数设置为(可变)模板,并将参数转发给元组。哦,访问器可以/应该为const和nonconst重载,并返回对元组元素的适当引用…
但是说真的,这并不值得你为之流汗。只使用普通的std::tuple
。当然,除了你过分简化了问题,你做的事情与你告诉我们的不同。
继承可以解决您的问题。定义一个提供T1
内容的单参数基类,并使双参数版本继承它。
有三个数字:0、1和无穷大。
哦,计数从0开始,不是1!
template<typename... Ts>
struct first_type {}
template<typename T0, typename... Ts>
struct first_type {
typedef T0 type;
};
template<typename... Ts>
using FirstType = typename first_type<Ts...>::type;
template<typename T0, typename Rest, typename=void>
struct foo_impl;
template<typename... Ts>
struct foo_augment {};
template<typename T1>
struct foo_augment<T1> {
T1 m_t1;
T1 t1() const { return m_t1; }
T1 t1() { return m_t1; }
};
template<typename T0, typename... Ts>
struct foo_impl< T0, std::tuple<Ts...>, typename std::enable_if< (sizeof...(Ts)<2) >::type >:
foo_augment<Ts...>
{
// use FirstType<Ts...> to get at the second type of your argument pack
foo_impl( T0 t0, Ts... ts ):
m_t0(t0), foo_augment<Ts...>(ts...)
{};
T0 m_t0;
T0 t0() { return m_t0; }
T0 t0() const { return m_t0; }
};
template<typename T0, typename... Ts>
using foo = foo_impl<T0, std::tuple<Ts...>>;
现在,请注意上面有很多样板文件,比您使用的重复代码的数量要多得多。
代替...
的混乱,您可以为T1
使用"保留值"来表示"不在那里",就像void
一样。在这种情况下,可以对构造函数使用这个技巧:
template<typename... Ts, typename=typename std::enable_if< ((sizeof...(Ts)==0) == (std::is_same<T1, void>::value)) && (sizeof...(Ts)<2) >::type >
foo_impl( T0 t0, Ts&&... ts ):
m_t0(t0), foo_augment<Ts...>(std::forward<Ts>(ts)...)
{};
其中构造函数是可变的,但是SFINAE意味着如果T1
是void
,则Ts...
参数包必须为0个元素,如果T1
不是void
,则必须为1个元素。
(代码尚未编译,但基本设计应该是合理的)。
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 代码在main()中运行,但在函数中出现错误
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 编译包含字符串的代码时遇到问题
- 我在c++代码中生成了一个运行时#3异常
- 如何在linux终端中同时编译和运行c++代码
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 在Linux for Windows上编译C++代码时出错
- 我的字符计数代码计算错误.为什么
- 孤立代码块在结构中引发异常
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- Clang拒绝类模板的嵌套类仅通过专门化定义的代码是正确的吗
- 如果模板的错误代码在If(false)中,我必须专门化模板吗
- 下面的模板专门化代码是非标准的,或者是vs - c++中的错误
- 避免c++(部分)模板专门化中的代码重复
- 在模板专门化中优化循环和避免代码重复
- 避免专门化模板中的代码重复
- 这个模板部分专门化代码有什么问题?
- 即使具有显式实例化,也不会为显式专门化模板生成代码
- 在此代码示例中使用了哪种模板专门化