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

StackOverflow https://stackoverflow.com/questions/403929

Вопрос

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

#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();
}

Каков ожидаемый результат?"T" или 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".Определяется ли порядок перегрузки / специализации в данном случае текущим стандартом?

Это было полезно?

Решение

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

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

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

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

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

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

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

Другие советы

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top