2012-05-22 3 views
2

Как реализовать дополнительные параметры шаблона?Как реализовать дополнительные параметры шаблона?

Я хотел бы иметь класс MyStruct<T1,T2,T3>, где разрешено использовать только первый или два первых параметра. Теперь функции, которые обрабатывают MyStruct<T1,T2,T3>, также должны корректно обрабатывать неиспользуемые параметры шаблона.

Пример:

#include <iostream> 

template<class T1, class T2, class T3> 
struct MyStruct { 
    T1 t1; T2 t2; T3 t3; 
    MyStruct() {} 
    MyStruct(T1 const& t1_, T2 const& t2_, T3 const& t3_) 
    : t1(t1_), t2(t2_), t3(t3_) {} 
}; 

template<class T1, class T2, class T3> 
MyStruct<T1, T2, T3> myplus(MyStruct<T1, T2, T3> const& x, 
       MyStruct<T1, T2, T3> const& y) { 
    return MyStruct<T1, T2, T3>(x.t1 + y.t1, x.t2 + y.t2, x.t3 + y.t3); 
} 

int main() { 
    typedef MyStruct<int, double, std::string> Struct; 
    Struct x(2, 5.6, "bar"); 
    Struct y(6, 4.1, "foo"); 
    Struct result = myplus(x, y); 
    // (8, 9.7, "barfoo") 
    std::cout << result.t1 << "," << result.t2 << "," << result.t3; 
} 

Теперь я хотел бы изменить код так, что выше main() функция все еще работает, но следующий будет работать:

typedef MyStruct<std::string, int> Struct; 
// result: ("barfoo", 5) 
Struct result = myplus(Struct("bar", 2), Struct("foo", 3)); 

Или это:

typedef MyStruct<int> Struct; 
// result: (5) 
Struct result = myplus(Struct(2), Struct(3)); 

Думаю, boost::tuple использует подобный трюк, где вы можете использовать boost::tuple<A>, boost::tuple<A,B>, boost::tuple<A,B,C>, но я не уверен, как они это делают.

ответ

3

Если я правильно получить вам, что вы должны быть в состоянии передать параметры по умолчанию для шаблона:

template<class T1, class T2 = Default, class T3 = Default> 

Где вы можете substitue любой тип для Default.

+0

Я вижу, и функция 'plus()' будет работать, если я определяю 'operator + (Default const & Default const &)', который возвращает простой 'Default()'. Ницца. – Frank

1

Вы могли бы сделать осознанный «неиспользуемый» тип:

namespace detail { struct unused { }; } 

template <typename T1, typename T2 = detail::unused, typename T3 = detai::unused> 
struct MyStruct 
{ 
    typedef T1 type1; 
    typedef T2 type2; 
    typedef T3 type3; 

    explicit MyStruct(type1 const & t1, 
         type2 const & t2 = type2(), 
         type3 const & t3 = type3()) 
    : x1(t1), x2(t2), x3(t3) 
    { } 

private: 
    type1 x1; 
    type2 x2; 
    type3 x3; 
}; 
+1

Я не думаю, что положить 'Unused' в анонимное пространство имен - это хорошая идея - если' MyStruct' помещается в заголовок, разные единицы перевода получат разные 'Unused', вызывая разные 'MyStruct' и нарушая ОДР. – ildjarn

+0

@ildjarn: Хорошая точка, исправлена. –

3

Вы можете сделать это, используя VARIADIC шаблоны, в C++ 11 (тяжелее и способ более сложный вариант); или вы можете использовать параметры шаблона по умолчанию, так как Boost.Tuple:

// boost/tuple/tuple/detail/tuple_basic.hpp 

// -- null_type -------------------------------------------------------- 
struct null_type {}; 

//... 

// - tuple forward declaration ----------------------------------------------- 
template < 
    class T0 = null_type, class T1 = null_type, class T2 = null_type, 
    class T3 = null_type, class T4 = null_type, class T5 = null_type, 
    class T6 = null_type, class T7 = null_type, class T8 = null_type, 
    class T9 = null_type> 
class tuple; 
+0

Просто примечание, так как в документах boost говорится: «Текущая версия поддерживает кортежи с 0-10 элементами». Так что здесь не так много волшебства. Просто жесткий код верхнего предела с использованием значений по умолчанию до этого предела. – Falmarri

Смежные вопросы