Prevent code duplication in a custom template

I want to have two similar patterns: one with one parameter and the other with two parameters:

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; } }; 

Note code duplication for all T1 related materials. How can i avoid this?

+7
source share
5 answers

The only solution for this is to have as much code as possible in the base class. For example:

 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) {} }; 
+7
source

This is a very general question.

In this case, you can put the material associated with T1 in the base class. In general, you should avoid a problem with one or two. What you are doing here can also be achieved with std::tuple , which is also part of the Boost library.

For what it's worth, tuple works by creating any number of base classes.

+2
source

By carefully examining your code, you override std::tuple . Exchange methods t1 and t2 for the free function std::get<N> , and you have everything (and possibly more) std::tuple gives you. For convenience, if it should be a method, consider the following:

 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); } }; 

For //! : Of course, you can make this constructor a (variable) template and just forward the arguments to the tuple. Oh, and the accessor can / should be overloaded for constants and nonconst and return the corresponding links to the tuple elements ...

But seriously, it's not worth the sweat. Just use plain std::tuple . Except, of course, you have simplified the problem, and you are doing something different from what you told us.

+2
source

Inheritance will solve your problem. Define a one-parameter base class that provides T1 material and make the two-parameter version inherited.

0
source

There are three numbers: 0, 1 and infinity.

Oh, and the countdown starts at 0, not 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...>>; 

Now notice that there are many patterns above, a fair amount more than the amount of duplicated code that you used.

Instead of clutter ... you can use the "reserved value" for T1 to indicate no, for example void . In this case, you can use this trick with the constructor:

  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)...) {}; 

where the constructor is a variable, but SFINAE means that the package of parameters Ts... must be 0 elements iff T1 is void and must be 1 element iff T1 not void .

(The code has not yet been compiled, but the basic design should be sound).

0
source

All Articles