// 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])'
// ???
Run Code Online (Sandbox Code Playgroud)
找到了两个解决方案:
a)在problem2.cpp中:
template<> void func<char[4]>(const char (&v)[4]) { }
template<> void func<char[15]>(const char (&v)[15]) { }
Run Code Online (Sandbox Code Playgroud)
b)在问题.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) { }
Run Code Online (Sandbox Code Playgroud)
抱歉,akappa,必须再次进行编辑以阐明它们是两个独立的解决方案...
akappa:我向此问题添加内容的唯一方法是对其进行编辑。我既不能评论,也不能添加答案。可能与»Stack Overflow需要来自另一个域的外部JavaScript(该域被阻止或加载失败)有关。«我不知道如何解决,因为我不知道SO到底是想告诉我那里。
函数特化很棘手,因为它们必须与参数的类型完全匹配。对于数组(字符串文字也是数组),编译器将执行类型推导并找出确切的类型,然后在程序中查找该特定符号。
特别是, 的类型ca是char[4],因此在调用模板时,推导的类型是 ,T == char[4]并且它期望找到的函数签名是void func<>( const char (&)[4] )
对于您的两个解决方案,它们是完全不同的方法。在第一种情况下,您将模板专门用于所使用的特定类型。这将变得很痛苦,因为对于您使用的每个新字符串文字大小或类型,您将需要手动添加专门化。顺便说一句,这就是为什么模板应该(通常)在标头中定义的原因,这样您就不需要在显式实例化中命名所有可能的模板参数(*) ...
第二种解决方案完全不同。在这种情况下,您将创建第二个不相关(在某种程度上)的基本模板。该基本模板正在获取指向数组第一个元素的指针,并用该指针调用原始模板,从而有效地更改类型(并在此过程中丢失信息:现在丢失了大小)。此时,所有对数组的调用都将与第二个模板匹配,并作为对带有指针的原始模板的调用转发,从而减少了专门化数组大小的需要(编译器解决了这些专门化问题)。
另请注意,如果您只想允许传递 char 数组,则调度程序模板不需要接受所有类型,它可以有一个非类型参数:
template <std::size_t N>
void f( const char (&a)[N] ) { f( &a[0] ); }
Run Code Online (Sandbox Code Playgroud)
加起来:
避免函数的模板特化,因为处理起来很麻烦。数组的类型包括大小,这又意味着您需要专门针对每个潜在的数组大小。或者,您可以添加一个辅助模板,它将分派到您的原始模板,执行到指针的转换。
* 请注意,如果每个和所有特化的实现都是相同的,您可以避免特化(和复制代码),同时通过在 .cpp 中提供模板的定义来保持相同的行为,然后手动实例化模板:
template <typename T> void func( T const & ) {
// code goes here
}
template void func<int>( int const & );
template void func<double>( double const & );
//...
Run Code Online (Sandbox Code Playgroud)