重载时在定义之前声明函数模板



C++Primer第五版在第16.3章(讨论函数模板重载的一章)的末尾有一段建议:

在定义任何功能。这样你就不必担心编译器是否会在它看到您要调用的函数之前实例化一个调用。

那么,这是否告诉我,在重载解析期间选择候选和可行的函数时,编译器可能会实例化一个最终没有选择的函数模板?我试着看看这是否真的会发生:

template<class> struct always_false : std::false_type {};
template <typename T> void test(T const &){
    static_assert(always_false<T>::value, "If this fires, it is instantiated");
}
template <typename T> void test(T*) {   }
int main(){
    int *q = nullptr; 
    test(q); //test(T*) should be the best match
}

如果test(T const &)以任何形式实例化,该程序都会引发编译器错误,除非该程序按预期编译良好。那么,这个提示是为了保护我免受什么样的编译灾难呢?在看到我试图调用的函数之前,它什么时候会实例化一个函数?

作者警告您:

template<class> struct always_false : std::false_type {};
template <typename T> void test(T const &){
   static_assert(always_false<T>::value, "If this fires, it is instantiated");
}
int main(){
    int *q = nullptr; 
    test(q); //test(T*) will not be matched.
}
template <typename T> void test(T*)
{ 
}

这些:

template<class> struct always_false : std::false_type {};
template <typename T> void test(T const &){
   static_assert(always_false<T>::value, "If this fires, it is instantiated");
}
template <> void test<int>(int const &);
void test(int *);
int main(){
   int *q = nullptr; 
   test(q); //test(int*) should be the best match
   int a;
   test(a); // test<int>(int const&) should be the best match
}
template <> void test<int>(int const &)
{
}
void test(int *)
{ 
}

如果您不提供声明

template <> void test<int>(int const &);
void test(int *);

main之前,它们不会在main中匹配。

我看到了很多SO问题,这是的一些变体

template<class T, class... Ts>
T sum(T t, Ts... ts) { return t + sum(ts...); }
// ^                               |
// |--------------------------------
//    only one visible in 
//     definition context
template<class T>
T sum(T t) { return t; }
int main() {
    sum(1, 2); // doesn't compile
}

(退货类型并不完美,但你已经明白了。)

当它没有编译时,人们会感到惊讶。

或者,更有趣的是,

template<class T> void f(T t) { f((int)t); }
void f(int) { /*...*/ }
int main() { 
    f(1L); // infinite recursion
}

最新更新