为什么在模板中我们可以使用从属名称而无需实例化而无需声明呢?

问题描述

我已经编写了这段代码来了解template名称查找:

//void bar(int);

template <typename T>
void foo(T x)
{
    bar(x);
}

void bar(int x)
{
    std::cout << "bar(int)\n";
}

template <int>
void foo(int i)
{
    bar(i);
}



int main()
{

    foo<int>(4);


    std::cout << "\ndone!\n";
}

我故意注释了函数bar(int)的声明。此功能bar(int)在模板功能dependent name中用作foo。因此它受实例约束。

  • 我已经在bar之后和foo专业化之前定义了foo<int>,以便后者可以看到bar(int)

但是当我编译代码时,出现此错误

‘bar’ was not declared in this scope,and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]|。如果我取消对bar(int)声明的注释,它可以正常工作吗?!

  • 如果在使用模板作为依赖名称之前必须先声明一个名称,那么为什么C ++允许实例化(如果不实例化)。 (如果我不“使用”模板化函数foo,则该代码有效)?

      template <typename U>
      void do_it(U u)
      {
          print(u); // not bound until instantiation
      }
    

那么允许在尚未声明的print(u)调用do_it并在实例化时失败的背后的想法是什么?

解决方法

在您的程序中,此定义:

template <int>     // not a specialization,just a different
void foo(int i)    // template with a non-type template parameter
{
    bar(i);
}

实际上并未定义foo主模板的专业化。因此,当您拨打电话时:

Foo<int>(4);

您最终调用了主模板。查找名称bar找不到该名称,您会收到错误消息。

如果相反,您实际上像这样为foo编写了int的专业化内容:

template <>           // specialization of primary
void foo<int>(int i)  // template foo with int
{
    bar(i);
}

然后调用foo<int>(4);就可以了,因为它调用了特殊化,并且此时查找bar确实找到了该名称。


现在回到您的程序(不进行专业化处理),如果从未实例化foo会发生什么,例如,因为没有调用?好的,程序仍然是错误的,但是编译器可能不会告诉您。这是您使用printdo_it描述的行为,这被正式称为病态,不需要诊断

,

请注意该错误输出中的行号。

您正在实例化第一个模板。第二个模板不是第一个模板的规范,而是一个功能模板,该模板需要一个未使用的int模板参数。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...