c++templates

Template : How to change a default typename to a typename that can't be changed?


struct ResultDeleter
{
    typedef HANDLE pointer;
    void operator()(pointer ptr) noexcept
    {
        ResultFree(ptr);
    }
};

template<typename P = std::unique_ptr<std::remove_pointer_t<HANDLE>, ResultDeleter>>
inline P ResultPointer(int val) noexcept
{
    return P(Result(val));
}

From what I understand, typename P = ... takes a default type that can be changed by the user. How can I write this to make it unchangeable? I need that typename for the return type, and I don't want to write it twice. I wrote it this way for RVO.

I tried finding what I need in the doc, but I just can't find the information to make me understand what I could do with it.

As requested by @3CEZVQ

#include <windows.h>
#include <memory>
#include <iostream>

struct Deleter
{
    typedef BSTR pointer;
    void operator()(const pointer ptr) noexcept
    {
        SysFreeString(ptr);
    }
};

template<typename P = std::unique_ptr<std::remove_pointer_t<BSTR>, Deleter>>
inline P BasicString(const LPCWSTR psz) noexcept
{
    return P(SysAllocString(psz));
}

int wmain()
{
    const auto ptr{ BasicString(L"Templates are not my cup of tea.") };
    std::wcout << ptr.get() << std::endl;
    return 0;
}

Solution

  • If the goal is just avoid of defining type aliases and using long type names in the code, then it can be

    #include <type_traits>
    
    inline std::unique_ptr<std::remove_pointer_t<BSTR>, Deleter> BasicString(
        LPCWSTR psz) noexcept {
      return std::invoke_result_t<decltype(BasicString), LPCWSTR>{
          SysAllocString(psz)};
    }
    

    And a better one

    inline auto BasicString(LPCWSTR psz) noexcept {
      return std::unique_ptr<std::remove_pointer_t<BSTR>, Deleter>{
          SysAllocString(psz)};
    }
    

    Calls to the first one compile faster in practice (Efficient C++: The hidden compile-time cost of auto return types.)

    As for me, I would make a new smart pointer class

    class ScopedBasicString {
     public:
      ScopedBasicString() = default;
      explicit ScopedBasicString(LPCWSTR psz);
      ScopedBasicString(const ScopedBasicString&) = delete;
      ScopedBasicString& operator=(const ScopedBasicString&) = delete;
      ScopedBasicString(ScopedBasicString&&) = default;
      ScopedBasicString& operator=(ScopedBasicString&&) = default;
    
      BSTR get() const {
        return bstr_;
      }
    
      // ...
    
     private:
      BSTR bstr_ = nullptr;
    };
    

    Or use _bstr_t class.