3

このコード フラグメント:

namespace ns
{
    struct last;

    struct first
    {
        typedef last next;
    };

    template <typename T>
    struct chain
    {
        chain<typename T::next> next;
    };

    template <>
    struct chain<last>
    {
    };
}

using namespace ns;

template <typename T>
void f(const T& x)          // #1
{
    f(x.next);
}

void f(const chain<last>&)  // #2
{
}

int main()
{
    f(chain<first>());
}

Comeau では次のエラーが発生し、GCC では非常によく似たエラーが発生します。

"ComeauTest.c", line 27: error: class "ns::chain<ns::last>" has no member "next"
    f(x.next);
        ^
          detected during:
            instantiation of "void f(const T &) [with T=ns::chain<ns::last>]"
                      at line 27
            instantiation of "void f(const T &) [with T=ns::chain<ns::first>]"
                      at line 36

#2ただし、が の前に定義されている#1場合、またはlastが の外で宣言されている場合はコンパイルされnsます。

これについての説明はありますか?

4

2 に答える 2

3

ケース 1)

template <typename T>
void f(const T& x)          // #1
{
    f(x.next); //where's f ??
}

void f(const chain<last>&)  // #2
{
}

上記を指定して、それ#2がテンプレートの特殊化であることを確認する必要があります#1template<>void f(const chain<last>&) // #2

Withouttemplate<> void f(const chain<last>&)は のオーバーロードとして解釈されfます。f(x.next);したがって、の宣言が欠落しているため、への呼び出しは形式が正しくありませんvoid f(const chain<last>&)

関数テンプレートの上にオーバーロードの宣言を追加すると、コードがコンパイルされます。

ソリューション:

1)

template <typename T>
void f(const T& x)          // #1
{
    f(x.next); //hmm specialized version down there.
}

template<>
void f(const chain<last>&)  // #2
{
}

2)

void f(const chain<last>&); // #0

template <typename T>
void f(const T& x)          // #1
{
    f(x.next); //hmm I can see #0, call #2
}

void f(const chain<last>&)  // #2
{
}

ケース 2)

void f(const chain<last>&)  // #2
{
}

template <typename T>
void f(const T& x)          // #1
{
    f(x.next); // found!!
}
于 2010-10-18T17:14:13.133 に答える
0

与えられた

template <typename T>
void f(const T& x)          // #1
{
    f(x.next);
}

void f(const chain<last>&)  // #2
{
}

...f最初の本体の への呼び出しは、2 番目の を呼び出すことはできません。これは、その時点でf2 番目が表示されないためです。f

したがって、最初に入ると、f最初のエラーまで再帰します。:-)まだインスタンス化されていないnext型である限り、ここではコンパイル時の再帰について話しています。f

そして、コールインmain...

int main()
{
    f(chain<first>());
}

...は 2 番目の引数の型と一致しないfため、必ず最初の を呼び出します。chain<first>f

これにより、 type の再帰呼び出しf(arg が生成されchain<last> )ます。に属性がないため、f引数の型をインスタンス化しようとするとchain<last>エラーが発生します。nextchain<last>

の宣言をグローバル名前空間に配置すると、コンパイルが正常に行われるように見えるコードについては、lastわかりません。本気ですか?注:実際のコンパイラでこれを試したことはありません。

乾杯 & hth.,

于 2010-10-18T20:03:09.433 に答える