2015-07-17 2 views
4

У меня есть тип со строгим требованием к выравниванию (из-за используемых операций AVX), который больше, чем выравнивание по умолчанию для платформ.Специализирующийся std :: make_shared

Чтобы использовать этот класс проще, я бы хотел специализироваться на std::make_shared, чтобы всегда использовать подходящий распределитель для этого типа.

Что-то вроде этого:

namespace std{ 
    template<class... Args> inline 
    auto make_shared<X, Args...>(Args&&... args){ 
     return std::allocate_shared(allocator_type<X, 32>, std::forward<Args>(args)...); 
    } 
} 

Мой вопрос, как это допускается стандартом? Будет ли он работать, как ожидалось?

+0

Вы не можете использовать 'alignas'? – dyp

+1

@dyp Нет, или хорошо, да, я уже это сделал, но это не будет работать для распределений кучи из-за [этого] (http://stackoverflow.com/questions/21895038/how-use-alignof-to-force- Расстановка-для-а-кучного-распределения). Эта специализация заключается в том, чтобы выравнивание применялось даже в куче в большинстве распространенных случаев использования. –

ответ

9

От N4140 [namespace.std]/1 (курсив мои):

Поведения C++ программа не определена, если оно добавляет декларацию или определения для патезраса или к пространству имен в пределах пространства имен станда если не указано иное. Программа может добавлять специализированную специализацию для любого стандартного шаблона библиотеки в пространство имен std, только если декларация зависит от пользовательского типа, и специализация соответствует стандартным требованиям библиотеки для исходного шаблона и явно не запрещена.

Поскольку вы добавляете специализированную спецификацию шаблона, которая зависит от определенного пользователем типа, это допустимое расширение пространства имен std.

Однако, как указано @dyp, вы не можете частично специализировать шаблоны функций. Ваши лучшие варианты состоят в том, чтобы явно указать аргументы для конструктора X (проиграть при безупречной переадресации) или просто написать функцию make_shared_x (потерять согласованность).

+0

Именно то, что я хотел. Я вспомнил, что было правило для этого, но не знал точных условий, при которых это было законным. Вы видите какие-то недостатки в этом? –

+1

@EmilyL. Вы не можете частично специализировать шаблон функции, и поэтому каждая специализация шаблона функции должна быть полной (или явной) специализацией. Поэтому вы не можете реализовать совершенную переадресацию, используя эту лазейку. (И вы не можете использовать его в общих чертах для набора типов, таких как шаблон шаблона.) – dyp

+0

Хак, я только что увидел специализацию шаблона в 'std' и достиг этой цитаты, не обращая внимания на специализацию шаблона частичной функции. Может быть, @EmilyL. было бы лучше просто написать функцию 'make_shared_x'. – TartanLlama

4

Это то, что я в конечном итоге делает, чтобы получить общее решение, которое не предполагает много шаблонного:

namespace xtd{ 
    template< typename T, std::size_t align = std::alignment_of<T>::value, typename... Args > 
    std::shared_ptr<T> make_shared(Args&&... args){ 
     // Platform specific knowledge. 
#if defined(_WIN64) || defined(_WIN32) 
#if defined(_WIN64) 
     const std::size_t default_alignment = 16; 
#else 
     const std::size_t default_alignment = 8; 
#endif 
#else 
#error "Only windows for now" 
#endif 

     if (align > default_alignment) { 
      typedef aligned_allocator<T, align> alloc_type; 
      return std::allocate_shared<T, alloc_type>(alloc_type(), std::forward<Args>(args)...); 
     } 
     else { 
      return std::make_shared<T>(std::forward<Args>(args)...); 
     } 
    } 
} 

Тогда я нашел Поиск & Заменить std::make_shared с xtd::make_shared :)

Я хочу это было бы в стандарте ...

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