Какой компилятор подходит для следующего поведения перегрузки / специализации? - PullRequest
4 голосов
/ 31 декабря 2008

Рассмотрим следующий код:

#include <stdio.h>

namespace Foo {
  template <typename T>
  void foo(T *, int) { puts("T"); }

  template <typename T>
  struct foo_fun {
    static void fun() { foo((T *)0, 0); };
  };
}

namespace Foo {
  void foo(int *, int) { puts("int"); }
}

using namespace Foo;

int main() {
  foo_fun<int> fun;
  fun.fun();
}

Каков ожидаемый результат? "Т" или int?

Один компилятор (gcc 4.0.1 из Apple Xcode 3.1.2) выводит "int", два других компилятора (gcc 4.1.2 и 4.1.3) выводят "T".

Если я перемещу объявление / определение foo (int *, int) перед версией foo (T *, int), все выдают «int». Порядок перегрузки / специализации в этом случае определяется действующим стандартом?

Ответы [ 2 ]

9 голосов
/ 31 декабря 2008

Второй void foo(... - это перегрузка (а не специализация), которая не видна при определении foo_fun::fun, поэтому она не будет найдена в контексте определения шаблона. Поскольку T* является зависимым типом, разрешение foo в выражении foo((T*)0, 0) будет отложено до времени создания шаблона и также будет учитываться контекст создания. Однако 14.6.4.2 стандарта гласит, что если имя функции является unqualified-id , но не template-id , то для функций поиска без ADL только функции, видимые в точке Определение шаблона рассматриваются. В пространстве имен Foo отсутствуют аргументы функций, поэтому поиск в зависимости от аргументов не происходит, поэтому вызывается версия шаблона foo, а не перегрузка без шаблона.

Большое спасибо litb за исправления к этому ответу.

Если вы сделали его специализацией, как показано ниже, то, поскольку специализации выбираются во время создания шаблона, специализация может быть вызвана, если соответствующая специализация видна в точке, в которой шаблон функции создается впервые для int .

namespace Foo {
    template<>
    void foo<int>(int *, int) { puts("int"); }
}

Глава 14 действующего стандарта, но она не очень читаема:)

Редактировать: Если бы мне пришлось выбирать наиболее релевантную часть стандарта, это, вероятно, было бы 14.6 [temp.res], параграф 9. (Немного сокращено) Если имя не зависит от шаблона-параметра объявление для этого имени должно находиться в области действия в том месте, где имя появляется в определении шаблона; имя привязано к объявлению, найденному в этой точке, и на эту привязку не влияют объявления, видимые в момент создания экземпляра.

Редактировать, редактировать: Но вам также необходимо принять во внимание 14.6.4.2 [temp.dep.candidate]. Очень сложно и опасно пытаться ссылаться на стандарт из-за всех взаимозависимостей, этот ответ является наглядным примером.

0 голосов
/ 31 декабря 2008

Как правило, из двух версий компилятора более поздняя версия, скорее всего, будет более стандартной.

...