4

GCC 4.6 不接受以下代码:

void F(int x,char y)
{
}
template<typename T>
void G(T t)
{
    F(t);
}
void F(int x)
{
}

int main()
{
    G(5);
    return 0;
}

应该是吗?

如果没有,是否有人有解决方法的好主意?发生这种情况的真实世界场景是 G 是用于解决特定类型问题的库的一部分,需要一个名为 F 的用户提供的辅助函数。但是,对于不同类型的问题,F 采用不同数量的参数。库附带了一些 F 的示例实现。

发生的情况是,根据客户端使用的#include-order,只有 F 的“错误类型”可能在模板声明时可见,然后 GCC 放弃,而不等到用户提供正确的 F被定义为。即使模板实例化发生在定义正确的 F 之后也是如此。

更新:是的,我知道如果 F 的所有声明都发生在 G 之前,或者如果 F 的所有声明都发生在 G 之后,它会起作用。但是,这对我并没有太大帮助。

更新:在这个最小示例改编的代码中,F 真的被称为“读取”。并且第一个 read 声明与第二个完全没有关系。第一个声明在一个头文件中,第二个在另一个头文件中。我不想介绍有关包含文件顺序的“奇怪”规则,尤其是当“读取”的版本彼此无关时。

4

4 回答 4

4

在实例化时,只进行参数相关的查找。您可以使用类型位于您的命名空间中的参数来解决您的问题F

void F(int x,char y)
{
}
template<typename T>
void G(T t)
{
    F(t);
}
void F(int x)
{
}

template<typename T>
struct wrapper {
 operator T() const { return t; }
 T t;
};

template<typename T> wrapper<T> make_wrapper(T t) {
  wrapper<T> w = { t };
  return w;
}

int main()
{
    G(make_wrapper(5));
    return 0;
}
于 2012-11-04T22:13:39.430 回答
1

一种可能的解决方法是确保声明在声明void F(int x)之前可用template<typename T> void G(T t);

void F(int x);

template<typename T> void G(T t) { .... }

在您的示例中,F(int)从属名称,so 在两阶段查找的第二阶段进行查找。但是,查找规则。在草案 n3337 的第 14.6.4 节中指定,指定名称必须在模板的定义点可见,或在与函数参数类型关联的命名空间中(参数依赖查找):

在解析从属名称时,会考虑来自以下来源的名称:

— 在模板定义时可见的声明。

— 来自实例化上下文 (14.6.4.1) 和定义上下文中与函数参数类型相关联的命名空间的声明。

因此,另一种解决方法是将函数带入T.

于 2012-11-04T21:49:43.093 回答
0

尝试将F(int)重载放在上面 G

void F(int x) {}

template <typename T> void G(T t) { F(t); } // works

函数没有被提升;在使用它们之前,您必须对它们进行原型设计或定义。

于 2012-11-04T21:49:39.363 回答
0

如果没有,是否有人有解决方法的好主意?

在您定义该模板时,F()编译器唯一知道的是void F(int x,char y),这显然与G(T t).

解决方案很简单:在定义void F(int x) 之前定义或声明template<typename T> void G(T t)

于 2012-11-04T21:50:55.577 回答