2014-01-19 4 views
3

Предположим, что я написал общие функции отображения для кортежей STL (кортеж, пара), а также последовательности STL (вектор, список, deque). Теперь я хочу написать глобальную функцию карты, вызывающую соответствующие специальные функции с учетом типов ввода.Специализируется на пакете параметров шаблона по умолчанию

У меня есть кое-что вдоль линий

template <typename... Ts> 
struct mappable { 
    static constexpr bool is_instance = false; 
}; 

template <typename... Tuples, typename = require<all<is_stl_tuple, Tuples...>::value>> 
struct mappable<Tuples...> { 
    template <typename Func> 
    auto map(Func&& f, Tuples&&... ts) { 
    return tuple::map(std::forward<Func>(f), ts...); 
    } 

    static constexpr bool is_instance = true; 
}; 

template <typename... Sequences, typename = require<all<is_stl_sequence, Sequences...>::value>> 
struct mappable<Sequences...> { 
    template <typename Func> 
    auto map(Func&& f, Sequences&&... seqs) { 
     return sequence::map(std::forward<Func>(f), seqs...); 
    } 

    static constexpr bool is_instance = true; 
}; 

template <typename Func, typename... Ts> 
auto map(Func&& f, Ts&&... ts) { 
    static_assert(mappable<Ts...>::is_instance, "Tried calling map on unsupported types. Mappable arguments must be supplied."); 
    return mappable<Ts...>::map(std::forward<Func>(f), std::forward<Ts>(ts)...); 
} 

Хотя мы надеемся, самообъясняющими тип проверки функции DEFS:

// true iff Unary<Ts>::value... == true for at least one Ts 
template <template <typename> class Unary, typename... Ts> 
struct any; 

// true iff Unary<Ts>::value... == true for all Ts 
template <template <typename> class Unary, typename... Ts> 
struct all; 

template <bool B> 
using require = typename std::enable_if<B>::type; 

Очевидно, что это не будет (и не) работать, так как я специализируются на аргументах по умолчанию. Есть ли способ сделать это, а если нет (и мне нужно перепроектировать), как бы вы решили перепроектировать эти функции? Последовательность :: Карта должна, например, взять любую комбинацию СТЛ последовательностей, так что все идеи у меня есть о реструктуризации просто перекладывать проблему в другом месте ...

Заранее спасибо за любую помощь ...

Edit: As просьба здесь примеры использования (на самом деле мой тестовый код для него) перед тем я начал делать выше:

auto t0 = std::make_tuple(2.f, -5, 1); 
auto t1 = std::make_tuple(1, 2); 
auto b0 = tuple::map([] (auto v) { return v > decltype(v)(0); }, t0); 
auto r0 = tuple::map([] (auto v0, auto v1) { return v0 + v1; }, t0, t1); 
// b0 is tuple<bool, bool, bool>(true, false, true) 
// b1 is tuple<float, int>(3.f, -3) 

и для последовательностей:

std::vector<float> s0 = {1.f, 2.f, 3.f, 0.f}; 
std::list<int> s1 = {3, 0, -2}; 
auto r = sq::map([] (auto v0, auto v1) { return v0 + v1; }, s0, s1); 
// type of r is compound type of first argument (vector here), result is 
// vector<float>(4.f, 2.f, 1.f) 

Реализации этих функций карты совершенно разные - цель моего подхода выше - уметь отбрасывать пространство имен и просто использовать карту, чтобы она делала «Правильную вещь».

+0

Кстати, вы злоупотребляя 'forward'. Это только для * выведенных * типов. –

+0

И можете ли вы привести пример использования? –

+0

@KerrekSB: 1. Вы имеете в виду std :: forward ... и std :: forward ... Надеюсь, и я буду прав. 2. Отредактировал вопрос, чтобы дать некоторые примеры ... –

ответ

5

Почему не только две перегрузки функции?

template <typename Func, typename... Tuples, 
    require<all<is_stl_tuple, Tuples...>>...> 
auto map(Func&& f, Tuples&&... ts) { 
    return tuple::map(std::forward<Func>(f), std::forward<Tuples>(ts)...); 
} 

template <typename Func, typename... Sequences, 
    require<all<is_stl_sequence, Sequences...>>...> 
auto map(Func&& f, Sequences&&... seqs) { 
    return sequence::map(std::forward<Func>(f), std::forward<Sequences>(seqs)...); 
} 

, что делает использование подстройки к require, для двух перегруженных играть хорошо:

template <bool condition> 
struct require_impl {}; 

template <> 
struct require_impl<true> { 
    enum class type {};  
}; 

template <typename Condition> 
using require = typename require_impl<Condition::value>::type; 
+0

У меня есть эквивалентная проблема с этим, поскольку компилятор называет второе переопределением первого - вы можете скомпилировать этот код? –

+0

@ RichardVock теперь я, пришлось переориентировать некоторые из ваших вещей. –

+0

Прежде всего, спасибо за работу (должен был предоставить всю реализацию). Что я заметил об этом решении, так это то, что ваш тип возврата будет недействительным. enable_if имеет второй параметр шаблона, чтобы заменить это, поэтому я мог теоретически использовать decltype (xyz :: map (...) для этого, однако возвращаемый тип tuple :: map (...) зависит от std :: tuple_size , поэтому я получаю ошибку компиляции. Тем не менее, ваши ответы меня направляют в правильном направлении, и проблема, которую я все еще имею, больше похожа на отдельный вопрос;) Upvote и accept следует за несколькими минутами ... –

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