9

clang と gcc の両方がこのコードを拒否します。

template<int i>
struct ambiguous
{
    static const int value = i;
};

namespace N
{
    template<int i>
    void ambiguous();

    int i = ambiguous<3>::value; // finds the function template name
}

ただし、どちらも次のコードを受け入れます。

struct ambiguous
{
    static const int value = 0;
};

namespace N
{
    void ambiguous();

    int i = ambiguous::value;
}

標準では、名前の前の名前のルックアップは、::「特殊化が型である名前空間、型、およびテンプレートのみを考慮する」と述べています。このコードを拒否するのにclangとgccは正しいですか? もしそうなら、私は何が欠けていますか?

C++ Working Draft Standard n3337 から

3.4.3 修飾名検索 [basic.lookup.qual]

クラスまたは名前空間のメンバーまたは列挙子の名前は、そのクラス、名前空間、または列挙を示す入れ子になった名前指定子に :: スコープ解決演算子 (5.1) を適用した後に参照できます。nested-name-specifier 内の :: スコープ解決演算子の前に decltype-specifier がない場合、 :: の前にある名前の検索では、特殊化が types である名前空間、型、およびテンプレートのみが考慮されます。見つかった名前が名前空間、クラス、列挙、または依存型を指定していない場合、プログラムは不適切な形式です。

14.2 テンプレートの特殊化の名前 [temp.names]

template-name がテンプレート引数によって明示的に修飾されるためには、その名前が template を参照するために知られている必要があります

名前ルックアップ (3.4) の後、名前がテンプレート名であるか、operator-function-id またはliteral-operator-id がオーバーロードされた関数のセットを参照しており、そのメンバーのいずれかが関数テンプレートである場合、これが続く場合a の<場合、 the<は常に template-argument-list の区切り文字として使用され、小なり演算子として使用されることはありません

編集

式と宣言の間のあいまいさとこの問題の混同を避けるために、非型パラメーターの代わりに型パラメーターを使用するテンプレートを使用した元のコードを次に示します。

template<class>
struct ambiguous
{
    static const int value = 0;
};

namespace N
{
    template<class>
    void ambiguous();

    int i = ambiguous<int>::value; // finds the function template name
}

これにより、すべての場合で同じエラーが発生します。は<演算子として解釈できません。

ambiguousは明確にテンプレート名ですが、型または関数のいずれかである可能性があります。関数または型のどちらに名前を付けるかを知らなくても、テンプレート ID 全体を解析し、後であいまいさを解決することができます。標準は、実装者がこれを行うことを許していますか?

4

2 に答える 2

3

内側の名前空間のテンプレートは、外側の名前を隠しているようです。

template<int i>
struct A
{
    static const int value = 0;
};

struct B
{
    static const int value = 0;
};

typedef A<0> C;


namespace N
{
    // The local function A is not declaced, yet, but the global A is:
    int early_e = A<3>::value; // Ok: The A in the global namespace. [simple-template-id}

    template<int i>
    int A() { return 0; }
    int B() { return 0; }
    int C() { return 0; }

    int a = A<3>();        // Ok: The A in the namespace. [simple-template-id}
    int b = N::A<3>();     // Ok: The A in the namespace. [N::simple-template-id]
    int c = ::N::A<3>();   // Ok: The A in the namespace. [::N::simple-template-id]
    int d = ::A<3>::value; // Ok: The A in the global namespace. ::simple-template-id::identifier]
    // The local function A is no type: "templates whose specializations are types"
    int e = A<3>::value;   // Error: The namespace has the function name A,
                           // which hides the global A. [simple-template-id::identifier]
    // The local function B is no type, but the global B is a type:
    int f = B::value;      // Ok: The B in the global namespace. [class-name::identifier]
    // The local function C is no type, but the global typedef C is a type:
    int g = C::value;      // Ok: The C in the global namespace. [typedef-name::identifier]
}

int main() {
    return 0;
}
于 2013-08-19T10:43:52.563 に答える