C ++: Почему имя зависит от конструктора, а не от функции-члена stati c - PullRequest
0 голосов
/ 24 января 2020

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

Справочная информация

В моем исходном вопросе меня интересовала перегрузка функции std::make_shared для работы с частично указанными аргументами шаблона:

std::make_shared<Container<1>::Internal>(arguments...);

Internal и Container являются структурами, которые оба имеют один шаблонный аргумент, полученный из Internal. (Полный код доступен ниже). Принятое решение прекрасно работает, если указать аргумент шаблона Container напрямую (1 в строке выше).

Проблема / вопрос

Затем я попытался указать аргумент шаблона из отличается constexpr context:

std::make_shared<Container<A>::Internal>(arguments...);

где A - аргумент шаблона третьей структуры, в которой расположена строка выше. Здесь я понял, что

  1. ... В конструкторе строка не работает и должна быть изменена на std::make_shared<Container<A>::template Internal>(arguments...);
  2. ... В функции-члене строка отлично работает.

Вопрос

Почему это так?

Код

Код можно опробовать здесь .

#include <memory>
#include <type_traits>

/// Container that is used in order to partially specify template arguments
template <int A> struct Container {
  /// Contained type, of which the template arguments are deduced.
  template <int B> struct Internal {
    explicit Internal(std::integral_constant<int, B> fu) { (void)fu; }
  };
};

/// Own make shared function / overload
namespace std {
template <template <int> typename partial, typename... Args> auto make_shared(Args &&... args) {
  using target_type = decltype(partial{std::declval<Args>()...});
  return std::make_shared<target_type>(std::forward<Args>(args)...);
}
} // namespace std

/// Some struct which uses its own template argument in order to create
template <int A> struct Producer {
  template <typename... T> explicit inline Producer(T &&... t) noexcept {
    auto const works = std::make_shared<Container<1>::Internal>(std::forward<T>(t)...);
    // XXX: the following fails if "template" is omitted
    auto const fails = std::make_shared<template Container<A>::Internal>(std::forward<T>(t)...);
  }

  template <typename... T> static auto test(T &&... t) noexcept {
    /// XXX: Here, it works without specifying "template"
    return std::make_shared<Container<A>::Internal>(std::forward<T>(t)...);
  }
};

int main() { Producer<1>{std::integral_constant<int, 8>{}}; }

Компиляция

  • Используемый компилятор: g++-9.1 и g++-10.0.
  • Команда компиляции: g++ -std=c++2a sol.cc

Ошибка

Следующее сообщение об ошибке генерируется, когда я опускаю 'template' в конструкторе.

sol.cc: In instantiation of ‘Producer<A>::Producer(T&& ...) [with T = {std::integral_constant<int, 8>}; int A = 1]’:
sol.cc:34:58:   required from here
sol.cc:25:29: error: dependent-name ‘Container<A>::Internal’ is parsed as a non-type, but instantiation yields a type
   25 |     auto const fails = std::make_shared<Container<A>::Internal>(std::forward<T>(t)...);
      |                        ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sol.cc:25:29: note: say ‘typename Container<A>::Internal’ if a type is meant

Собственные мысли по поводу проблемы

Во время name lookup компилятор определяет, обозначает ли имя тип / шаблон или нет.

Если имя не может быть найдено до тех пор, пока фактические аргументы шаблона не станут известны, это dependent-name. Из того, что я понимаю, что это здесь (по крайней мере, в конструкторе). Следовательно, в конструкторе компилятор не может определить, что Internal обозначает шаблон, тогда как в функции-члене stati c это так.

Это может быть причиной того, что Container<A>::Internal является зависимой name в конструкторе, в случае если компилятор автоматически определяет тип структуры. Но в моем случае использования я явно заявляю это (Producer <1> в main ()).

Примечание

Я попытался предоставить более простой пример , но в этом Например, эта ошибка не возникла, я думаю, что то, что я предоставил выше, является относительно минимальным.

1 Ответ

1 голос
/ 25 января 2020

В предоставленном вами коде функция test нигде не вызывается, поэтому она никогда не создается. Если бы он был создан, то в результате отсутствия template компилятор должен был бы диагностировать его как некорректно сформированный.

...