Consider the following example, consisting of 4 files.
Outer.h
#pragma once
#include "genericAlgorithm.h"
class Outer
{
private:
struct Inner {}; // Note that Inner is private
const Inner inner;
public:
Outer() : inner() {}
inline void method()
{
genericAlgorithm(inner);
}
};
genericAlgorithm.h
#pragma once
template <typename T>
void genericAlgorithm(const T& value);
genericAlgorithm.cpp
#include "genericAlgorithm.h"
#include "Outer.h"
template <typename T>
void genericAlgorithm(const T& value) {}
// Explicit template instantiation (compiles on GCC, Clang; error C2248 on MSVC)
template void genericAlgorithm<Outer::Inner>(const Outer::Inner& value);
main.cpp
#include "Outer.h"
int main()
{
Outer outer;
outer.method();
return 0;
}
As you can see, in genericAlgorithm.cpp
there is an explicit instantiation of genericAlgorithm()
function template for argument Outer::Inner
, which is a private inner struct of class Outer
.
It is my understanding that this is legal, since, according to cppreference.com...
Explicit instantiation definitions ignore member access specifiers: parameter types and return types may be private.
And in fact, this code compiles perfectly fine on GCC 6.3 and Clang 4.0.
However, MSVC (Visual Studio 2017 15.2) seems to take issue with it and produces the following compilation error:
genericalgorithm.cpp(9): error C2248: 'Outer::Inner': cannot access private struct declared in class 'Outer'
So, is this a bug in MSVC or am I missing something and in fact there is a problem with my code that needs to be fixed? If so, does it mean that it's GCC and Clang, along with cppreference.com, who are wrong?
UPDATE: I believe I found a relevant passage in §14.7.2 [templ.explicit] (item 12) of n4296 and n4567 working drafts of the standard:
The usual access checking rules do not apply to names used to specify explicit instantiations. [Note: In particular, the template arguments and names used in the function declarator (including parameter types, return types and exception specifications) may be private types or objects which would normally not be accessible and the template may be a member template or member function which would not normally be accessible. — end note]
Unless I'm misinterpreting what's written, it seems that this behaviour of MSVC is indeed non-compliant. Granted, these are just drafts - I unfortunately don't have access to the actual $133 per copy standard, so I can't be sure if this item has been retained.