Странная ошибка компиляции относительно разрешения перегрузки - PullRequest
3 голосов
/ 18 октября 2010

Этот фрагмент кода:

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.

Есть объяснение этому?

Ответы [ 2 ]

3 голосов
/ 18 октября 2010

Дело 1)

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

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

Необходимо убедиться, что #2 является шаблоном специализации #1, указав template<> выше void f(const chain<last>&) // #2

Без template<> 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!!
}
0 голосов
/ 19 октября 2010

Учитывая

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

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

... вызов f в теле первого никогда не может вызвать второй f, потому что второй f не виден в этой точке.

Итак, если вы попадете в первый f, то он вернется к первой ошибке.:-) Я говорю здесь о рекурсии времени компиляции, если next относится к типу, для которого f еще не создан.

И вызов в main, ...

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

... обязательно вызывает первый f, поскольку chain<first> не соответствует типу аргумента второго f.

Это приводит к рекурсивному вызову f( arg типа chain<last> ).И при попытке создать экземпляр f для типа аргумента chain<last> вы получите ошибку, поскольку в chain<last> нет атрибута next.

Относительно кода, который явно компилируется при размещении объявления last в глобальном пространстве имен я не знаю.Уверены ли вы?Примечание: я не пробовал ничего с настоящим компилятором.

Cheers & hth.,

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...