У меня есть несколько дополнительных вопросов к сценарию, который я описал здесь , я нашел этот пост особенно полезным для рассуждений о моей проблеме.
Справочная информация
В моем исходном вопросе меня интересовала перегрузка функции 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
- аргумент шаблона третьей структуры, в которой расположена строка выше. Здесь я понял, что
- ... В конструкторе строка не работает и должна быть изменена на
std::make_shared<Container<A>::template Internal>(arguments...);
- ... В функции-члене строка отлично работает.
Вопрос
Почему это так?
Код
Код можно опробовать здесь .
#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 ()).
Примечание
Я попытался предоставить более простой пример , но в этом Например, эта ошибка не возникла, я думаю, что то, что я предоставил выше, является относительно минимальным.