3

I have the task of porting some code to c++20. Part of it is an templated allocator that handles some of the odd needs or Microsoft COM objects so we can use them in vectors. In part, it allocates/deallocates memory via CoTaskMemAlloc/CoTaskMemFree It also provides specializations of construct and destroy which have gone way in c++20.

For Example:

// VARIANT

inline void CnvCoTaskAlloc<VARIANT>::construct(VARIANT* p, const VARIANT& val){
    ::VariantCopy( p, const_cast<VARIANT*>( &val ) );
}

inline void CnvCoTaskAlloc<VARIANT>::destroy(VARIANT* p){
    ::VariantClear( p );
}

I am having a hard time working out how to migrate this code to c++20. If I could find an example of doing something similar that implements construct, I am pretty sure it would be obvious.

Thanks in Advance.

Otis
  • 33
  • 2
  • Does this answer your question? [Customizing std::allocator\_traits::construct](https://stackoverflow.com/questions/58985619/customizing-stdallocator-traitsconstruct) – 康桓瑋 Apr 14 '22 at 17:12
  • this confused me as well. it is not that the specialization has gone way, but rather that the specialization is not necessary to fulfill the concept of Allocator. You can still customize construct and destruct as a member. do not specialize the trait. – alfC Apr 14 '22 at 17:13

1 Answers1

0

The standard has the following to say about specializing standard library templates ([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 standard specifies the following behaviour for std::allocator_traits<Alloc>::construct ([allocator.traits.members]/5):

template<class T, class... Args>
  static constexpr void construct(Alloc& a, T* p, Args&&... args);

Effects: Calls a.construct(p, std::forward<Args>(args)...) if that call is well-formed; otherwise, invokes construct_at(p, std::forward<Args>(args)...).

So, if you choose to specialize std::allocator_traits<MyAlloc>::construct, it must do basically the same thing as the primary template: it will call MyAlloc::construct if possible, otherwise construct_at.

This suggests that specializing std::allocator_traits is generally not what you want to do. Instead, just like pre-C++20, you just need to make sure that MyAlloc::construct contains the logic that you want. If you want the default, you can even omit MyAlloc::construct entirely, and std::allocator_traits will take care of it.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • Brian, This pointed me at the underlying issue. My brain misparsed the actual error and missed that we were using a template elsewhere that depended on std::allocator::construct. Changing that to use allocator::traits let it pick up the implementation for our custom one. Thanks. – Otis Apr 18 '22 at 19:17