Jonathan Wood
Jonathan Wood

Reputation: 67355

Can't return std::unique_ptr<> with derived type

I have the following templated function:

template<typename T = CRecordset>
std::unique_ptr<T> ExecuteSqlQuery(LPCTSTR pszSqlQuery = nullptr, RecordsetMode nMode = RecordsetMode::read)
{
    ASSERT(m_Database.IsOpen());
    std::unique_ptr<ITableRecordset> prs = std::make_unique<T>(&m_Database);
    if (!ExecuteSqlQuery(prs.get(), pszSqlQuery, nMode))
        prs.reset();
    return prs;
}

And I'm calling it like this:

auto prs = db.ExecuteSqlQuery<CCustomerRecordset>(nullptr, RecordsetMode::bulkRead);

CCustomerRecordset derives from CTableRecordset<>, and CTableRecordset<> derives from ITableRecordset.

However, the return statement in the function gives me an error:

Error C2440 'return': cannot convert from std::unique_ptr<ITableRecordset,std::default_delete<_Ty>>' to 'std::unique_ptr<CCustomerRecordset,std::default_delete<_Ty>>'  
    with  
    [  
        _Ty=ITableRecordset  
    ]  
    and  
    [  
        _Ty=CCustomerRecordset  
    ]

Since CCustomerRecordset is a type of ITableRecordset, why can't I do this?

Upvotes: 1

Views: 543

Answers (1)

Your example reduces to this:

struct A {};
struct B : A {};

A *a = new B;
B *b = a;

The return statement is trying to return a unique_ptr<ITableRecordset> where a unique_ptr<CCustomerRecordset> is expected. It's a downcast, and won't happen implicitly. A way to fix it would be to make full use of the concrete type throughout the function template. So instead of converting to the interface:

auto prs = std::make_unique<T>(&m_Database); 

Upvotes: 2

Related Questions