假设我有以下功能:
template<typename T> inline
typename std::enable_if<has_member_foo<T>::value,int>::type
foo( T const &t ) {
return t.foo();
}
template<typename T> inline
typename std::enable_if<!has_member_foo<T>::value,int>::type
foo( T const& ) {
return 0;
}
template<typename T> inline
int call_foo( T const &t ) {
return sizeof( T ) + foo( t );
}
这大部分工作正常,但如果我稍后为特定类型添加重载:
inline int foo( std::string const &s ) {
return s.size();
}
我在 call_foo()
的定义后添加,
call_foo()
不使用重载。
但是,如果我在call_foo()
的定义之前移动重载代码,则使用它。
为什么第一种情况下不使用过载?
当call_foo()
在代码中的其他地方使用时被实例化,
编译器已经看到重载,
那为什么不使用呢?
请注意,我的原始代码将foo()
函数作为模板化foo_traits
类的静态成员函数,同样使用enable_if
进行保护。 那个代码工作,即模板类特化,即使在 call_foo()
之后提供了,为什么不使用独立的重载函数?
如果重要,我在Mac OS X 10.7.4上使用g++
4.6。
答案 0 :(得分:3)
如果你将标准(无论如何是C ++ 98)转换为14.6.4.2/1,你会读到:
对于依赖于模板参数的函数调用,如果是 函数名是一个unqualified-id但不是一个template-id, 使用通常的查找规则找到候选函数(3.4.1, 3.4.2)除了:
- 对于使用非限定名称查找(3.4.1)的查找部分, 只有来自模板的外部链接的函数声明 找到了定义上下文。
在这种情况下,template-id
表示<template-params>
限定的模板名称。这非常清楚地说明了您在程序中观察到的内容,即只考虑在模板定义的上下文中可见的函数。当你考虑它时,如果情况并非如此,那么基于跟随的内容来改变模板的含义会非常容易,这会导致违反一个定义规则。