稍后添加模板函数的特化

时间:2012-07-12 14:12:01

标签: c++ templates template-specialization

假设我有以下功能:

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。

1 个答案:

答案 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>限定的模板名称。这非常清楚地说明了您在程序中观察到的内容,即只考虑在模板定义的上下文中可见的函数。当你考虑它时,如果情况并非如此,那么基于跟随的内容来改变模板的含义会非常容易,这会导致违反一个定义规则。