Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

MSVC insists on using inaccessible member from private-inherited base class, although it was re-defined as public

Consider this code (godbolt example):

#include <cstddef>

template< std::size_t... sizes >
class Impl
{
public:
    static constexpr std::size_t
    getDimension()
    {
        return sizeof...( sizes );
    }
};

template< std::size_t... sizes >
class Wrapper : private Impl< sizes... >
{
    using BaseType = Impl< sizes... >;

public:
    //using BaseType::getDimension;
    static constexpr std::size_t
    getDimension()
    {
        return BaseType::getDimension();
    }
};

template< typename A, typename B >
class Combine : public B
{
public:
    static_assert( A::getDimension() > 0 );
    static_assert( B::getDimension() > 0 );
    static_assert( A::getDimension() == B::getDimension(),
                   "dimensions of A and b do not match" );
};

int main()
{
    Combine< Impl< 0 >, Wrapper< 0 > > a;
}

Trying to compile with MSVC (v19 with /std:c++17 /permissive-) leads to this error:

example.cpp
<source>(32): error C2247: 'Impl<0>::getDimension' not accessible because 'Wrapper<0>' uses 'private' to inherit from 'Impl<0>'
<source>(8): note: see declaration of 'Impl<0>::getDimension'
<source>(40): note: see declaration of 'Wrapper<0>'
<source>(40): note: see declaration of 'Impl<0>'
<source>(32): error C2248: 'Impl<0>::getDimension': cannot access private member declared in class 'Wrapper<0>'
<source>(8): note: see declaration of 'Impl<0>::getDimension'
<source>(40): note: see declaration of 'Wrapper<0>'
<source>(40): note: see reference to class template instantiation 'Combine<Impl<0>,Wrapper<0>>' being compiled
<source>(34): error C2247: 'Impl<0>::getDimension' not accessible because 'Wrapper<0>' uses 'private' to inherit from 'Impl<0>'
<source>(8): note: see declaration of 'Impl<0>::getDimension'
<source>(40): note: see declaration of 'Wrapper<0>'
<source>(40): note: see declaration of 'Impl<0>'
<source>(34): error C2248: 'Impl<0>::getDimension': cannot access private member declared in class 'Wrapper<0>'
<source>(8): note: see declaration of 'Impl<0>::getDimension'
<source>(40): note: see declaration of 'Wrapper<0>'
Compiler returned: 2

However, the code compiles fine with state-of-the-art compilers like GCC and Clang, so I assume the code is correct. Is there a workaround for MSVC? Note that the private inheritance has a purpose in the real world.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

An ugly workaround exists. First, you might define an external template function for delegating to the proper class:

template<typename T>
constexpr std::size_t getDimension()
{
    return T::getDimension();
}

This is so that MSVC’s name resolution won’t try to search in the private base classes. Then, you might write:

template< typename A, typename B >
class Combine : public B
{
public:
    static_assert( ::getDimension<A>() == ::getDimension<B>(),
                   "dimensions of A and b do not match" );
};

The :: is not mandatory, it’s only for cases where getDimension() would also take template arguments as a member function.

This hack uses the fact that it’s a static member function; if you have a non-static member function, you need to pass this as well.

Example: https://godbolt.org/z/4fax9dGvd


An alternative solution is to wrap the call to an inner struct:

template< typename A, typename B >
class Combine : public B
{
public:
    static struct {
        static_assert( A::getDimension() == B::getDimension(),
                       "dimensions of A and b do not match" );
    } verify;
};

This does not require a global template function to delegate, but neither is ran direcly inside your class (which might or might not be a problem).

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading