I have a type with a strict alignment requirement (due to AVX operations being used) that is larger than the platforms default alignment.
To make usage of this class simpler, I would like to specialize std::make_shared
to always use a suitable allocator for this type.
Something like this:
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)...);
}
}
My question is, is this allowed by the standard? Will it work as expected?
From N4140 [namespace.std]/1 (emphasis mine):
The behavior of a C++program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.
Since you are adding a template specialization which depends on a user-defined type, this is a valid extension of the std
namespace.
However, as pointed out by @dyp, you can't partially specialize function templates. Your best options would be to explicitly specify the arguments to the X
constructor (losing out on perfect-forwarding), or just write a make_shared_x
function (losing out on consistency).
This is what I ended up doing to get a generic solution that doesn't involve a lot of boilerplate:
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)...);
}
}
}
Then I find Search & Replace std::make_shared
with xtd::make_shared
:)
I wish this would be in the standard...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With