首页 > 解决方案 > C ++:为什么名称依赖于构造函数,而不是静态成员函数

问题描述

对于我在这里描述的场景,我有一些后续问题,我发现这篇文章对于推理我的问题特别有帮助。

背景

在我最初的问题中,我有兴趣重载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. ...在成员函数中,该行工作正常。

问题

为什么会这样?

代码

代码可以在这里试用。

#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>{}}; }

汇编

错误

当我在构造函数中省略“模板”时,会生成以下错误消息。

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>)。

笔记

我试图提供一个更简单的示例,但在该示例中没有发生此错误,我认为我上面提供的内容相对较少。

标签: c++templatesname-lookup

解决方案


在您提供的代码中,该test函数不会在任何地方调用,因此它永远不会被实例化。如果要对其进行实例化,那么由于缺少template,编译器将需要将其诊断为格式错误。


推荐阅读