2

考虑以下示例,由 4 个文件组成。



外层.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);
    }
};


通用算法.h

#pragma once

template <typename T>
void genericAlgorithm(const T& value);


通用算法.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);


主文件

#include "Outer.h"

int main()
{
    Outer outer;
    outer.method();
    return 0;
}

如您所见,argument 有一个函数模板genericAlgorithm.cpp的显式实例化,它是 class 的私有内部结构。genericAlgorithm()Outer::InnerOuter

我的理解是这是合法的,因为根据cppreference.com ...

显式实例化定义忽略成员访问说明符:参数类型和返回类型可能是私有的。

事实上,这段代码在 GCC 6.3 和 Clang 4.0 上编译得非常好。

但是,MSVC (Visual Studio 2017 15.2)似乎对此有异议并产生以下编译错误:

genericalgorithm.cpp(9): error C2248: 'Outer::Inner': cannot access private struct declared in class 'Outer'

那么,这是 MSVC 中的错误,还是我遗漏了什么,实际上我的代码有问题需要修复?如果是这样,是否意味着 GCC 和 Clang 以及 cppreference.com 错了?


更新:我相信我在标准的n4296n4567工作草案的§14.7.2 [templ.explicit](第 12 项)中找到了相关段落:

通常的访问检查规则不适用于用于指定显式实例化的名称。[注意:特别是,函数声明器中使用的模板参数和名称(包括参数类型、返回类型和异常规范)可能是通常无法访问的私有类型或对象,并且模板可能是成员模板或成员函数通常无法访问。——尾注]

除非我误解了所写的内容,否则 MSVC 的这种行为似乎确实不合规。当然,这些只是草稿——不幸的是,我无法获得每份 133 美元的实际标准,因此我无法确定该项目是否已被保留。

4

1 回答 1

0

我认为这意味着显式实例化定义忽略了您显式指定的事物中的访问说明符。它不会神奇地授予您访问其他项目的私人成员的权限。

类型“Inner”对于您用作参数的东西是私有的,而不是输入 genericAlgorithm

于 2017-11-06T18:32:10.343 回答