Specializing std::make_shared

Specializing std::make_shared

本文关键字:shared make Specializing std      更新时间:2023-10-16

我有一个具有严格对齐要求的类型(由于使用了AVX操作),它比平台默认对齐要大。

为了使该类的使用更简单,我想对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)...);
    }
}

我的问题是,这是标准允许的吗?它会像预期的那样起作用吗?

From N4140 [namespace. cn]/1(强调我的):

c++程序的行为是未定义的,如果它向命名空间std或命名空间std中的命名空间添加声明或定义,除非另有说明。程序可以添加模板专门化只有当声明依赖于用户定义的类型且专门化满足原始模板的标准库要求且未被明确禁止时,才能将任何标准库模板命名为std。

由于您正在添加依赖于用户定义类型的模板专门化,因此这是std名称空间的有效扩展。

然而,正如@dyp所指出的,你不能部分专门化函数模板。您的最佳选择是显式地指定X构造函数的参数(失去了完美转发),或者只是编写make_shared_x函数(失去了一致性)。

这就是我最终得到一个不涉及大量样板文件的通用解决方案:

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)...);
        }
    }
}

然后我找到Search &将std::make_shared替换为xtd::make_shared:)