C++:为什么名称依赖于构造函数,而不是静态成员函数
C++: Why is name dependent in constructor, not in static member function
我对我描述的场景有一些后续问题 , I found this post 特别有助于推理我的问题。
背景
在我最初的问题中,我感兴趣的是重载 std::make_shared
函数来处理部分指定的模板参数:
std::make_shared<Container<1>::Internal>(arguments...);
Internal
和Container
是结构体,它们都有一个模板参数,Internal
中的一个是派生的。 (完整代码在下面可用)。当直接指定 Container
的模板参数(上一行中的 1
)时,公认的解决方案非常有效。
问题/问题
然后我尝试从不同的constexpr
上下文指定模板参数:
std::make_shared<Container<A>::Internal>(arguments...);
其中 A
是上面一行所在的第三个结构的模板参数。
在这里我意识到,
- ... 在构造函数中,该行不起作用,必须更改为
std::make_shared<Container<A>::template Internal>(arguments...);
- ...在成员函数中,该行工作正常。
问题
为什么会这样?
代码
代码可以试用here。
#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 表示模板,而在静态成员函数中,它是。
这可能是 Container<A>::Internal
在构造函数中作为从属名称的原因,以防编译器自动推导结构的类型。
但在我的用例中,我明确说明了它(Producer<1> in main())。
备注
我试过提供一个simpler example,但是在那个例子中并没有出现这个错误,我觉得呢
我上面提供的比较少。
在您提供的代码中,test
函数未在任何地方调用,因此它永远不会被实例化。如果要实例化它,那么由于缺少 template
,编译器将需要将其诊断为格式错误。
我对我描述的场景有一些后续问题
背景
在我最初的问题中,我感兴趣的是重载 std::make_shared
函数来处理部分指定的模板参数:
std::make_shared<Container<1>::Internal>(arguments...);
Internal
和Container
是结构体,它们都有一个模板参数,Internal
中的一个是派生的。 (完整代码在下面可用)。当直接指定 Container
的模板参数(上一行中的 1
)时,公认的解决方案非常有效。
问题/问题
然后我尝试从不同的constexpr
上下文指定模板参数:
std::make_shared<Container<A>::Internal>(arguments...);
其中 A
是上面一行所在的第三个结构的模板参数。
在这里我意识到,
- ... 在构造函数中,该行不起作用,必须更改为
std::make_shared<Container<A>::template Internal>(arguments...);
- ...在成员函数中,该行工作正常。
问题
为什么会这样?
代码
代码可以试用here。
#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 表示模板,而在静态成员函数中,它是。
这可能是 Container<A>::Internal
在构造函数中作为从属名称的原因,以防编译器自动推导结构的类型。
但在我的用例中,我明确说明了它(Producer<1> in main())。
备注
我试过提供一个simpler example,但是在那个例子中并没有出现这个错误,我觉得呢 我上面提供的比较少。
在您提供的代码中,test
函数未在任何地方调用,因此它永远不会被实例化。如果要实例化它,那么由于缺少 template
,编译器将需要将其诊断为格式错误。