2017-11-06 4 views
1

4つのファイルからなる次の例を考えてみましょう。MSVCが引数としてプライベートタイプの明示的なテンプレートインスタンス化をコンパイルできない



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); 


genericAlgori thm.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; 
} 

あなたが見ることができるように、genericAlgorithm.cppである引数Outer::Inner、用genericAlgorithm()関数テンプレートの明示的なインスタンスがありますクラスOuterのプライベート内部構造体。

... cppreference.comによると、以来、

Explicit instantiation definitions ignore member access specifiers: parameter types and return types may be private.

これが合法であることを私の理解されており、実際には、このコードはGCC 6.3とクラン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と間違っている人がいるのでしょうか?


UPDATE:私は「ない限り

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]

:私は、標準のn4296n4567ワーキングドラフトの§14.7.2[templ.explicit](項目12)で関連の通路を発見したと信じて書かれたことを誤解すると、MSVCのこの動作は実際には非準拠と思われます。確かに、これはドラフトだけです。残念ながら実際の$133 per copy標準にアクセスできないので、このアイテムが保持されているかどうかはわかりません。

答えて

0

明示的なインスタンス化定義では、明示的にを指定しているものがのアクセス指定子を無視することを意味しています。他のアイテムのプライベートメンバーへのアクセスを魔法のように許可するものではありません。

タイプ「インナー」彼らは何の問題もなく与えられた例をコンパイルするので、あなたは、GCCとクランの両方が、それは間違って得たことを言っているgenericAlgorithm

+0

を入力しないように、あなたが引数として使用されている事にプライベートのですか? – TerraPass

+0

私は確信よりも推測が多いので、私は "答え"をコメントとして書いて欲しいと思います。テンプレートを特化しているだけなので、他のタイプの私的メンバーにアクセスすることは許されません。しかし私は、GCCがVCよりも標準準拠性が高い傾向にあることをよく認識しています。 – Joe

+0

私は*明示的にインスタンス化*していますが、*テンプレートを特化していません*。実際にこの問題に遭遇したユースケースは、コンパイル時に(再)コンパイル時に.cppに移動され、対応するテンプレートが明示的にインスタンス化されたプロジェクト内にありました。これらのインスタンシエーションの1つに、この例のようなプライベートタイプが含まれていました。私には、private型を含むクラスのカプセル化を公開したり、テンプレートを友人として追加したりすることで、アクセス指定子を無視するのは非常に便利でした。 – TerraPass

関連する問題