-1

Here is an example of allocator from cppreference:

#include <cstdlib>
#include <limits>
#include <new>

template<class T>
struct Mallocator
{
    typedef T value_type;
    Mallocator() = default;
    template<class U>
    constexpr Mallocator(const Mallocator<U>&) noexcept
    {
    }

    [[nodiscard]] T* allocate(std::size_t n)
    {
        if (n > std::numeric_limits<std::size_t>::max() / sizeof(T))
            throw std::bad_array_new_length();

        if (auto p = static_cast<T*>(std::malloc(n * sizeof(T)))) {
            return p;
        }

        throw std::bad_alloc();
    }

    void deallocate(T* p, std::size_t n) noexcept { std::free(p); }
};

template<class T, class U>
bool operator==(const Mallocator<T>&, const Mallocator<U>&)
{
    return true;
}

template<class T, class U>
bool operator!=(const Mallocator<T>&, const Mallocator<U>&)
{
    return false;
}

It can be used as in examples 1 and 2 in the following snippet:

#include "mallocator.h"

#include <vector>

int mainF()
{
    std::vector<int, Mallocator<int>> v; // 1
    Mallocator<int>                   a;
    std::vector<int, Mallocator<int>> v2 { a }; // 2
    std::vector<int, Mallocator<int>> v3 { a }; // 2

    // std::vector<int> v4 { a }; // 3 (compilation error)

    return 0;
}

Is it possible to conform custom allocator so it will work as in example 3. If yes, how to do it?

2
  • No, since Class Template Argument Deduction prevents it. You can (since C++11 at least, I'm not sure about earlier, and haven't checked) define your own (distinct) vector type using something like template<class T, class Allocator = MyAllocator<T> > using YourVector = std::vector<T, Allocator>;. But you can't just force all code that explicitly uses std::vector to default to using an allocator other than std::allocator<T>. Commented Aug 24, 2024 at 9:36
  • Partial CTAD is not allowed. See the workarounds given in the dupes. Commented Aug 24, 2024 at 10:00

2 Answers 2

0

No, class template argument deduction (CTAD) doesn't allow this. But you can create a wrapper function and use partial template argument deduction with this function.

Something like this:

#include <memory>
#include <vector>

template <typename T, typename Allocator>
auto get_vector(const Allocator& a) {
    return std::vector<T, Allocator>{a};
}

int main() {
    // Insert your own allocator here.
    std::allocator<int> some_random_allocator;
    auto vec = get_vector<int>(some_random_allocator);
}
Sign up to request clarification or add additional context in comments.

Comments

0

std::vector<int> is implicitly std::vector<int, std::allocator<int>>, if you omit the second template argument it will be the default one, it will not be deduced from the constructor.

CTAD is all or none, so you can either generate your own alias, or apply CTAD to All template arguments.

#include "mallocator.h"
#include <vector>

template <typename T>
using MyVector = typename std::vector<T, Mallocator<T>>;

int main()
{
    std::vector<int, Mallocator<int>> v; // 1
    Mallocator<int>                   a;
    std::vector<int, Mallocator<int>> v2 { a }; // 2
    std::vector<int, Mallocator<int>> v3 { a }; // 2

    std::vector v4 { a }; // let CTAD deduce both

    MyVector<double> v5{ a };

    return 0;
}

godbolt example

note that you cannot have std::vector<double> v5{a}; because CTAD isn't invoked, and you will have std::vector<double, std::allocator<double>> v5{a}, which cannot compile.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.