模板函数调用被模板之前声明的错误签名的函数混淆

时间:2012-11-04 21:46:56

标签: c++ templates

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实际上被称为“读”。第一个阅读声明与第二个没有任何关系。第一个声明在一个头文件中,第二个声明在另一个头文件中。我不想引入关于包含文件顺序的“奇怪”规则,特别是当“读取”的版本彼此无关时。

4 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分: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)依赖名称,因此在两阶段查找的第二阶段中查找。但是,查询的规则。在n3337草案的§14.6.4中规定,指定名称必须在模板定义点或与函数参数类型相关联的命名空间中可见(参数依赖查找):

  

在解析依赖名称时,会考虑以下来源的名称:

     

- 在模板定义点可见的声明。

     

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

因此,另一种解决方法是将函数引入T的命名空间。

答案 2 :(得分:0)

尝试将F(int)重载置于 G之上。

void F(int x) {}

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

没有悬挂功能;你必须在使用它们之前制作原型或定义它们。

答案 3 :(得分:0)

  

如果没有,是否有人对解决方案有好主意?

在您定义该模板时,编译器已知的唯一F()void F(int x,char y),这显然与G(T t)中的用法不匹配。

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