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...);

InternalContainer是结构体,它们都有一个模板参数,Internal中的一个是派生的。 (完整代码在下面可用)。当直接指定 Container 的模板参数(上一行中的 1)时,公认的解决方案非常有效。

问题/问题

然后我尝试从不同的constexpr 上下文指定模板参数:

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

其中 A 是上面一行所在的第三个结构的模板参数。 在这里我意识到,

  1. ... 在构造函数中,该行不起作用,必须更改为 std::make_shared<Container<A>::template Internal>(arguments...);
  2. ...在成员函数中,该行工作正常。

问题

为什么会这样?

代码

代码可以试用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>{}}; }

编译

错误

当我在构造函数中省略'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,编译器将需要将其诊断为格式错误。