【发布时间】:2020-01-24 20:44:43
【问题描述】:
我对@987654321@ 描述的场景有一些后续问题,我发现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
错误
当我在构造函数中省略“模板”时,会生成以下错误消息。
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)。
注意
我试图提供一个simpler example,但在那个例子中这个错误没有发生,我想什么 我上面提供的比较少。
【问题讨论】:
-
尝试添加调用静态函数的语句。您的代码显式构造了一个对象,因此将调用构造函数,这会强制编译器诊断构造函数的代码,但不会在任何地方调用静态函数。模板的处理相当复杂,并且一些编译器非常积极地推迟模板实例化 - 这可能会影响编译器何时或是否有足够的信息来发出诊断
标签: c++ templates name-lookup