c++ - C ++:为什么名称依赖于构造函数,而不是静态成员函数
问题描述
对于我在这里描述的场景,我有一些后续问题,我发现这篇文章对于推理我的问题特别有帮助。
背景
在我最初的问题中,我有兴趣重载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...);
- ...在成员函数中,该行工作正常。
问题
为什么会这样?
代码
代码可以在这里试用。
#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
错误
当我在构造函数中省略“模板”时,会生成以下错误消息。
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
在构造函数中成为依赖名称的原因,以防编译器自动推断结构的类型。但在我的用例中,我明确说明了它(main() 中的Producer<1>)。
笔记
我试图提供一个更简单的示例,但在该示例中没有发生此错误,我认为我上面提供的内容相对较少。
解决方案
在您提供的代码中,该test
函数不会在任何地方调用,因此它永远不会被实例化。如果要对其进行实例化,那么由于缺少template
,编译器将需要将其诊断为格式错误。
推荐阅读
- templates - 如何使用来自另一个项目的文档模板
- powershell - 在 PowerShell 脚本中运行 quser.exe 在 IDE 中有效,但在作为服务运行时无效
- google-chrome-extension - 如何在当前标签中保存popup.html的状态?
- shell - 无法在受限 sudoer 用户上使用 Ansible
- c++ - C ++将向量的内容写入txt类?
- python-3.x - 划分两个数据帧给出 NaN
- python - ValueError:无法将大小为 7840000 的数组重塑为形状 (60000,784)
- algorithm - 具有多个循环的算法的时间复杂度
- mongodb - Pymongo 可以通过所有 mongoshell 命令吗
- ruby-on-rails - Rails 模型范围在控制台中返回未定义的方法