【问题标题】:How to make C++ find templated function header when dependent-scoped inner classes are involved?当涉及依赖范围的内部类时,如何使 C++ 找到模板化函数头?
【发布时间】:2014-09-16 12:58:46
【问题描述】:

我正在尝试构建一个模板化的 C++ 函数,该函数接受一个指向内部类对象的指针作为其参数。这是所涉及的类结构的简化版本,类似于典型的链表或树类:

template <typename T>
struct Outer
{
  struct Inner
  {
    T val;
    Inner (T v) : val(v) { }
  };

  Inner* ptr;

  Outer(T val)
  {
    ptr = new Inner(val);
  }
};

我已将它们制成结构以排除任何访问控制问题并删除了一些无关的实例变量。考虑到这个类结构,这里有三个函数,前两个不是我想要的:

template <typename T>
void testOuter (const Outer<T>& obj)
{
  cout << obj.ptr->val << endl;
}

void testInnerInt (const Outer<int>::Inner* p)
{
  cout << p->val << endl;
}

template <typename T>
void testInnerTemplated (const typename Outer<T>::Inner* p)
{
  cout << p->val << endl;
}

这第三个函数基本上是我想要的,在标题方面(当然,它旨在作为更大代码体中的辅助函数),但它不起作用。如果我编译并运行以下主函数:

int main()
{
  Outer<int> foo(5);

  cout << foo.ptr->val << endl;
  testInnerInt(foo.ptr);
  //testInnerTemplated(foo.ptr);
  testOuter(foo);
}

它运行得很好(打印5 三次),但如果我取消注释调用testInnerTemplated 的行,我会收到一个编译器错误,说no matching function for call to ‘testInnerTemplated(Outer&lt;int&gt;::Inner*&amp;)’(在g++ 4.9.1 中)。我猜这是模板查找或匹配的问题,但是我该如何告诉编译器如何解决呢?

【问题讨论】:

    标签: c++ templates inner-classes


    【解决方案1】:
    template <typename T>
    void testInnerTemplated(const typename Outer<T>::Inner*);
    

    编译器无法通过模板参数推导推导出T,因为这是标准中定义的非推导上下文:

    未推断的上下文是:

    使用限定 ID 指定的类型的嵌套名称说明符。一种模板 ID 类型,其中一个或多个模板参数是引用模板参数的表达式。

    当以包含非推导上下文的方式指定类型名称时,构成该类型名称的所有类型也都是非推导的。但是,复合类型可以包括推导类型和非推导类型。 [示例:如果将类型指定为A&lt;T&gt;::B&lt;T2&gt;,则TT2 都不是推导的。同样,如果将类型指定为 A&lt;I+J&gt;::X&lt;T&gt;IJT,则为非推导。如果类型指定为void f(typename A&lt;T&gt;::B, A&lt;T&gt;),则A&lt;T&gt;::B 中的T 是非推导的,但A&lt;T&gt; 中的T 是推导的。 ]

    【讨论】:

    • 我推测它不是在推断T,但这并不能真正告诉我如何解决我的问题。
    • @blahedo 要解决您的问题,要么显式提供模板参数 (testInnerTemplated&lt;int&gt;(foo.ptr)),要么在 Inner 中创建 T 的公共类型定义并调用包装函数模板 (template&lt;class T&gt; void foo(T x);) 调用testInnerTemplated&lt;typename T::type&gt;(x).
    【解决方案2】:

    如果您希望从Inner 中恢复来自Outer&lt;&gt; 的类型信息,您可以使用特征。

    template <typename T>
    struct Outer
    {
        typedef T TypeParam;
    
        struct Inner
        {
            typedef Outer<T> InnerOuter;
            T val;
            Inner (T v) : val(v) {}
        };
    
        Inner *ptr;
    
        Outer (T val) : ptr(new Inner(val)) {}
    };
    

    现在定义一个更通用的testInnerTemplated,但它使用特征来恢复传递给Outer&lt;&gt;的类型信息。

    template <typename T>
    void testInnerTemplated (const T * p)
    {
      typename T::InnerOuter::TypeParam val = p->val;
      std::cout << val << std::endl;
    }
    

    【讨论】:

      猜你喜欢
      • 2014-05-15
      • 1970-01-01
      • 1970-01-01
      • 2012-04-09
      • 2013-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-01
      相关资源
      最近更新 更多