2

У меня есть существующий шаблон для сопоставления медленных функций с коллекциями (в стиле одноименной функции clojure), которые я хочу ускорить с помощью «семантики перемещения» в аромате этого полезного сообщения в блоге не мной: http://blog.knatten.org/2012/11/02/efficient-pure-functional-programming-in-c-using-move-semantics/Могу ли я использовать специализированную специализацию или тип принуждения здесь?

Этот старый код, который я написал хорошо работает для меня:

template <typename function, 
     template <typename...> class collection, 
     typename in_type, 
     typename... types, 
     typename out_type = 
     typename std::result_of<function(in_type)>::type> 
static collection<out_type> pmap(
    const function& f, const collection<in_type, types...>& c) { 
    collection<out_type> result; 
    if(!c.empty()) { 
    result = collection<out_type>(c.size()); 
    __gnu_parallel::transform(c.cbegin(),c.cend(),result.begin(),f); 
    } 
    return result; 
} 

Поскольку я готов совершить выбрасывая сбор ввода, я должен быть в состоянии ускорить этот процесс в том случае, когда in_type это то же самое, что и out_type, написав над c вместо выделения всей новой коллекции. Я пробовал специализацию шаблона, но компилятор не мог выбрать в специальном случае, и я не мог придумать исправление. Вот моя попытка в какой-то ловкость рук:

template <typename function, 
     template <typename...> class collection, 
     typename in_type, 
     typename... types, 
     typename out_type = 
     typename std::result_of<function(in_type)>::type> 
static collection<out_type> pmap(
    const function& f, const collection<in_type, types...>&& c) { 
    collection<out_type> result; 
    if(!c.empty()) { 
    if(typeid(in_type)==typeid(out_type)) { 
     __gnu_parallel::transform(c.begin(),c.end(),c.begin(),f); 
     result = c; 
    } 
    else { 
     result = collection<out_type>(c.size()); 
     __gnu_parallel::transform(c.cbegin(),c.cend(),result.begin(),f); 
    } 
    } 
    return std::move(result); 
} 

Я предполагаю, что есть некоторые хак, что бы компилятор принимает результат = с (даже если он не должен заботиться в любом случае из-за заявления, если окружающие), но подобное кастинг заставляет меня чувствовать себя неловко. Любые предложения по исправлению или добавлению шаблона специализации для случая с записью?

ответ

2

typeid - это среда выполнения, поэтому вы пытаетесь выбрать поведение во время выполнения, а не время компиляции.

Вы можете написать две перегруженные и выбрать правильный с помощью std::enable_if:

template <typename function, 
     template <typename...> class collection, 
     typename in_type, 
     typename... types, 
     typename out_type = 
     typename std::result_of<function(in_type)>::type, 
     typename std::enable_if<!std::is_same<in_type, out_type>::value>::type* = nullptr> 
static collection<out_type> pmap(
    const function& f, collection<in_type, types...>&& c) { 
    collection<out_type> result; 
    result.reserve(c.size()); 
    __gnu_parallel::transform(c.cbegin(),c.cend(),std::back_inserter(result),f); 


    return result; 
} 

template <typename function, 
     template <typename...> class collection, 
     typename in_type, 
     typename... types, 
     typename out_type = 
     typename std::result_of<function(in_type)>::type, 
     typename std::enable_if<std::is_same<in_type, out_type>::value>::type* = nullptr> 
static collection<out_type,types...> pmap(
    const function& f, collection<in_type, types...>&& c) { 
    __gnu_parallel::transform(c.begin(),c.end(),c.begin(),f); 

    return std::move(c); 
} 
+0

Спасибо, ваш enable_if пример заставил меня идти. Я не уверен, что вы можете сделать это без семантики перемещения ... похоже, вы пишете const и в своей второй части, чего я никогда не пробовал. –

+0

О, извините, вам нужно будет взять неконстантную ссылку (или даже ссылку на rvalue), если вы хотите изменить 'c'. – TartanLlama

+0

Вы также пропустите 'types ...' для возвращаемого типа. Вы также можете вернуться по ссылке. – Jarod42

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