// problem.cpp:
#include <string>
template<typename T> void func(const T & v);
int main() {
int i;
float f;
char * cp;
char ca[4];
func(i);
func(f);
func(cp);
func(std::string("std::string"));
func(ca);
func("string_literal");
return 0;
}
// problem2.cpp
#include <string>
template<typename T> void func(const T & v);
// undefined reference to `void func<int>(int const&)'
template<> void func<int>(const int & v) { }
// undefined reference to `void func<float>(float const&)'
template<> void func<float>(const float & v) { }
// undefined reference to `void func<char*>(char* const&)'
template<> void func<char *>(char * const & v) { }
// void func<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
template<> void func<std::string>(std::string const & v) { }
// undefined reference to `void func<char [4]>(char const (&) [4])'
// ???
// undefined reference to `void func<char [15]>(char const (&) [15])'
// ???
找到两个解决方案:
a)在problem2.cpp中:
template<> void func<char[4]>(const char (&v)[4]) { }
template<> void func<char[15]>(const char (&v)[15]) { }
b)在problem.cpp中:
template<typename T, unsigned N> void func(const T (&v)[N]) { func(v+0); }
and then in problem2.cpp, add the newly missing
template<> void func<const char *>(const char * const & v) { }
抱歉,akappa,不得不再次编辑,以澄清它们是两个独立的解决方案......
akappa:我在这个问题上添加内容的唯一方法就是编辑它。我也不能评论,也不能添加答案。可能与某些事情有关»Stack Overflow需要来自另一个域的外部JavaScript,它被阻止或无法加载。«我不知道如何解决因为我不知道确切的SO试图告诉我那里。
答案 0 :(得分:3)
函数特化很棘手,因为它们必须与参数的类型完全匹配。对于数组(字符串文字也是数组),编译器将执行类型推导并找出确切的类型,然后它将在程序中查找该特定符号。
特别是ca
的类型是char[4]
,所以在调用模板时,推断的类型是T == char[4]
,它期望找到的函数签名是{{1} }
从您的两个解决方案来看,它们是完全不同的方法。在第一种情况下,您将专门针对所使用的特定类型的模板。这将变得很痛苦,因为您使用的每个新字符串文字大小或类型,您将需要手动添加专业化。顺便提一下,这就是为什么模板应该(通常不是)在标题中定义的原因,因此您不需要在显式实例化中命名所有可能的模板参数(* )功能 ...
第二种解决方案完全不同。在这种情况下,您将创建第二个无关(在某种程度上)基本模板。该基本模板正在获取指向数组的第一个元素的指针,并使用该模板调用原始模板,从而有效地更改类型(并在流程中丢失信息:现在大小已丢失)。此时,所有带数组的调用都将与第二个模板匹配,并作为对带有指针的原始模板的调用进行转发,从而减少了专门处理数组大小的需要(编译器会解析这些特化)。
另请注意,如果您只想允许传递char数组,则调度程序模板不需要接受所有类型,它可以有一个非类型参数:
void func<>( const char (&)[4] )
总结:
避免使用函数的模板特化,因为这些处理起来很麻烦。数组的类型包括大小,这反过来意味着您需要为每个可能的数组大小 specialize 。或者,您可以添加将分派到原始模板的辅助模板,执行转换为指针。
*请注意,如果每个和所有特化的实现相同,则可以通过在.cpp中提供模板的定义然后手动来避免专门化(和复制代码),同时保持相同的行为实例化模板:
template <std::size_t N>
void f( const char (&a)[N] ) { f( &a[0] ); }