Partial template specialization for: std::allocator_traits?
Asked Answered
O

1

1

Is it possible to specialize the std::allocator_traits, template like this?

namespace falloc_ {

  template<class Tp> class FAllocator ;

}

// partial spec for all falloc_::FAllocator<U>, std::allocator_traits

template<typename Tp> 
struct std::allocator_traits<falloc_::FAllocator<Tp> > {

 using allocator_type = falloc_::FAllocator<Tp> ;
 using value_type = typename allocator_type::value_type ;

 // ...
 // All the components I need here, I will include all the code if You need them.
 // ...

} ;


namespace falloc_ {

  template<class Tp> class FAllocator {

    public:
       using value_type = Tp ;
  
  } ;

}

The complete code compiles and runs in the std++20 allocator class and allocator, feature class (std::allocator_traits) specifications. In that case, my question is actually about practical correctness, whether according to people who know more about the standard, whether similar feature class overloading is forbidden, or simply assume that since the (complete) code is compileable and executable and works according to the intended plan - can I consider that I can use it?

Additionally, I tested the allocator with the code:

  std::vector<int, falloc_::FAllocator<int> > mv ;

  for (size_t i = 0 ; i < 5 ; i++) {
    mv.push_back(i) ;
  }

  for (int i = 4 ; i > -1 ; i--) {
    std::cout << "mv[" << i << "]: " << mv[i] << '\n' ;
  }

Memory was allocated and freed correctly, I also checked with, Valgrind. Using Gdb, I checked and all functions were called from

std::allocator_traits<falloc_::FAllocator<U> > // U aka int for std::vector<int, falloc_::FAllocator<int> > 

Thank You in advance for any insights, suggestions and advice.

Obtect answered 2/3, 2021 at 22:5 Comment(0)
B
2

Edit (February 22, 2023): As of C++23, it will no longer be permitted to specialize std::allocator_traits. See here for more information.

Prior to C++23, it was permitted to specialize the std::allocator_traits template. See [namespace.std]/2:

Unless explicitly prohibited, a program may add a template specialization for any standard library class template to namespace std provided that (a) the added declaration depends on at least one program-defined type and (b) the specialization meets the standard library requirements for the original template.

The thing is that such specializations weren't particularly useful (which is why there wasn't much opposition to banning them in C++23). User specializations of standard library templates must meet all requirements of the original template. The standard specifies the definition of each member type of std::allocator_traits<A> and the behaviour of each member function to such an extent that if you were to write your own specialization, it would basically be identical to the original, which defeats the purpose of doing so. (I suppose you could have done something like add logging statements to std::allocator_traits<...>::construct(...) without violating the original requirements, but it's easier to just put those logging statements in the allocator itself, and from C++23 onward, that's what you'll have to do.)

Bittersweet answered 2/3, 2021 at 22:28 Comment(12)
Thank You for Your answer. I would also like to thank You for the very good documentation that elucidates the topic and for delineating the issues. Ultimately, I would like to use my own memory heaps or memory arena. I already have some implementation of offset pointers and I need to use the c++ 17/20 standard. In standard 17/20 the function 'std :: allocator <...> :: construct' is being abandoned from the allocator level in favor of the function 'consructs' in std :: allocator_traits is another reason for trying to overload allocator_traits,Obtect
I asked just because I didn't think it was will work. I am generally interested in handling memory from a slightly lower level in relation to concurrent programming.Obtect
I want to get to know the issues in a theoretical outline in order to later be able to more practically create code based on allocators conspect, while helping other programmers if it will be useful to someone.Obtect
@Obtect the allocator_traits<A>::construct function calls A::construct. You should implement A::construct but use allocator_traits<A>::construct in generic code.Bittersweet
@BrianBi There is a quote in en.cppreference.com/w/cpp/memory/allocator_traits about C++23: "A program that declares an explicit or partial specialization of std::allocator_traits is ill-formed, no diagnostic required." Does it mean that in C++23 it is explicitly prohibited to specialize std::allocator_traits?Jarvis
@Jarvis Yes, I will update the answer accordingly.Bittersweet
This is also such a specialization (in the past, when I wrote it for the first time) was suspicious to me and I am glad that a more experienced creators, programmers helped me understand this issue to the end, also the standard itself began to displace similar constructions in favor of existing better "defined ones", like the ones You presented from the beginning, thanks again for Your interest and discussions.Obtect
@BrianBi yeah but if one cannot specialize std::allocator_traits and construct function has been removed from std::allocator, than how can one customize construct function?Labrie
@Labrie You can create your own allocator type A, which has a construct function. That function will be called by std::allocator_traits<A>::construct.Bittersweet
@BrianBi that is correct, but std::allocator::construct has been removed in c++20 now...Labrie
@Labrie Correct. As I said, you can create your own allocator type.Bittersweet
@BrianBi I see what you mean as construct was removed from std::allocator while it can be still in the custom allocatorsLabrie

© 2022 - 2024 — McMap. All rights reserved.