我想要两个相似的模板,一个带有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相关的内容的代码重复。我怎么能避免这个?
答案 0 :(得分:7)
唯一的解决方案是在基类中拥有尽可能多的代码。例如:
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) {}
};
答案 1 :(得分:2)
这是一个非常笼统的问题。
在这种情况下,您可以将T1
相关的东西放在基类中。一般来说,你应该避免一两个问题。你在这里做的也可以通过std::tuple
实现,它也是Boost库的一部分。
对于它的价值,tuple
通过编写任意数量的基类来工作。
答案 2 :(得分:2)
仔细查看您的代码,您将重新实现std::tuple
。交换免费功能t1
的{{1}}和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重载并返回对元组元素的适当引用...
但严重的是,这不值得汗流。背。只需使用普通//!
即可。当然,除了你过度简化问题,你做的事情与你告诉我们的不同。
答案 3 :(得分:0)
继承可以解决您的问题。定义一个提供T1
内容的单参数基类,并使双参数版本继承该内容。
答案 4 :(得分:0)
有三个数字: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)...)
{};
其中构造函数是variardic,但SFINAE意味着Ts...
参数包必须是0个元素iff T1
是void
,并且必须是1个元素iff T1
是不是void
。
(代码尚未编译,但基本设计应该是合理的)。