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

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

#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». Определен ли в данном случае порядок перегрузки / специализации действующим стандартом?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
0
272
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Второй void foo(... - это перегрузка (а не специализация), которая не видна в определении foo_fun::fun, поэтому не будет найдена в контексте определения шаблона. Поскольку T* является зависимым типом, разрешение foo в выражении foo((T*)0, 0) будет отложено до времени создания экземпляра шаблона, а также будет учитываться контекст создания экземпляра. Однако в 14.6.4.2 стандарта сказано, что если имя функции - неквалифицированный идентификатор, но не идентификатор шаблона, то для поиска, не относящегося к 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]. Очень сложно и опасно пытаться ссылаться на стандарт из-за всех взаимозависимостей, этот ответ является показательным.

Спасибо! в этом есть смысл. То есть вы говорите, что g ++ 4.0.1 от Apple не соответствует стандартам?

ididak 31.12.2008 23:29

Я бы рискнул и сказал, что да.

CB Bailey 31.12.2008 23:31

Я обновил код, используя пространство имен Foo (разница от компиляторов все еще есть). Объяснение контекста создания экземпляра звучит неубедительно.

ididak 01.01.2009 00:34

Обновился снова, мы доберемся до конца!

CB Bailey 01.01.2009 00:37

Да, здесь главное - 14.6.4.2.

ididak 01.01.2009 00:48

да, ваш ответ действительно правильный. Я обнаружил сейчас (что я уже подозревал, но не был уверен), что пример в 14.6 / 9 ошибочен (см. open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#197). только ADL происходит в точке интереса. удалил свой ответ, потому что он был основан на том некорректном примере

Johannes Schaub - litb 19.03.2009 16:35

также см. groups.google.com/group/comp.lang.c++.moderated/browse_threa‌ d /… для полезного обсуждения этого

Johannes Schaub - litb 19.03.2009 16:36

и действительно, текущий черновик n2800 уже содержит исправление. ура! :)

Johannes Schaub - litb 19.03.2009 16:42

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

В целом это правильно. Однако gcc от Apple включает в себя собственные исправления, которые вышли позже (с Xcode 3.1.2), чем gcc 4.1.2 / 3.

ididak 31.12.2008 23:54

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