2011-07-24 36 views
4

我正在学习/学习模板功能专业化规则。我开始使用此功能模板专业化帮助

template<typename T> 
std::string toString(const T& t) 
{ 
    ostringstream out; 
    out << t; 
    return out.str(); 
} 

现在,我想专门它为const char *

typedef const char* ccharPtr; 

template<> 
std::string toString(const ccharPtr& s) 
{ 
    cout << "in specialization" << endl; // just to let me know 
    return std::string(s); 
} 

我想要做的,没有一个typedef,但到目前为止,我想不通出来。

该特化适用于const char *,但不适用于char *。

const char* s1 = "Hi" 
cout << toString(s1); // works 
char s2[] = "There"; 
cout << toString(s2); // doesn't work, since s2 isn't const char* 
cout << toString(", Bob"); // doesn't work. Why not? 

我想单个专业化为每个案件工作,但无法解决它。

回答

1

我认为这应该工作:

template <typename T> 
    std::string to_string(const T &) 
{ 
    ... 
} 

// non templated 
std::string to_string(const char* x) 
{ 
    ... 
} 
+0

是的,它会工作取代strcpy,但我想学习模板特殊化。我知道这是一种人为的情况。 – John

+1

所以我想你可能不得不专门为const char *和char *一次。由于char *不是const char *,我猜C++不符合专业化,并使用更通用的功能。如果你想让const char *和char *都使用相同的特化,我想你必须明确地将你的参数从char *转换为const char *。 – neodelphi

+0

@John:你应该学习模板专业化的第一件事情之一是函数模板专业化很少有帮助。 – aschepler

6

为什么专门化?只是超载功能。完全专业化的功能模板通常不是必需的。

template <typename T> 
std::string toString(const T& in) 
{ 
    ostringstream out; 
    out << in; 
    return out.str(); 
} 

std::string toString(char const* in) 
{ 
    return in; 
} 

OK,如果你真的要做到这一点,那么你必须考虑到字符串文字—的类型,虽然他们含蓄转换char const* —是char const[N]

template <typename T> 
std::string toString(T const & t) { 
    ostringstream out; 
    out << t; 
    return out.str(); 
} 

template <> 
std::string toString(char const* const & s) { 
    cout << "(S1)"; 
    return std::string(s); 
} 

template <size_t N> 
std::string toString(char (&s)[N]) { 
    cout << "(S2)"; 
    return std::string(s); 
} 

template <size_t N> 
std::string toString(char const (&s)[N]) { 
    cout << "(S3)"; 
    return std::string(s); 
} 

int main() { 
    const char* s1 = "Hi"; 
    cout << toString(s1) << endl; 
    char s2[] = "There"; 
    cout << toString(s2) << endl; 
    cout << toString(", Bob") << endl; 
} 

// Output: 
// (S1)Hi 
// (S2)There 
// (S3), Bob 

Live demo.

可以省略专业化S2,然后双方"There"", Bob"将使用S3

被警告,实际上,这根本不是专业化的。我宁愿通过创建新的函数模板来作弊。但我必须得到size_t参数;你只能做真正专业化这里如果你N拿起一个价值,把它写进函数签名作为具体类型的一部分,或者如果你能部分专门的函数模板。

+0

但是如果我想要呢? – John

+0

传递一个字符串文字,然后它推导出一个数组类型,它不匹配指针类型(这是专门化,因此类型必须完全匹配)。随着你显示的重载,它将使用第二个'toString',因为转换序列是不明确的,但第二个是非模板,因此获胜。 –

+0

@John:看我的编辑。 –

6

它不起作用的原因是因为它实际上不是正确的类型。字符串文字不是const char*类型,它们的类型是const char[N]。当你传递一个字符串时,T被推断为char[N]。这是完全匹配,专业化不是。你不能规定字符串文字,因为这需要部分规范,而C++不支持部分功能专业化。

1

我在Sun Studio C++编译器中遇到类似的问题。首先,我使用了两个数组过载(有或没有constchar (&)[N])和两个指针过载(char*const char*)。

令我惊讶的是,如toString("quoted literal")这样的调用被使用,似乎不可能强制编译器选择数组过载。更有趣的是 - 对于像char lit[] = "literal",toString(lit)这样的参数选择了数组超载!

经过一番思考,我找到了一种方法,使代码的行为作为部分功能专业化。诀窍就是让SFINAE

首先使用,定义一个模板从(const) char[N]

template<typename T> 
    struct is_literal { 
}; 

template<size_t N> 
struct is_literal<const char[N]> { 
    typedef std::string type; 
    static const size_t len = N - 1; // subtract terminating null char from N 
}; 

template<size_t N> 
struct is_literal<char[N]> { 
    typedef std::string type; 
    static const size_t len = N - 1; 
}; 

template<> 
struct is_literal<const char*> { 
    typedef std::string ptr_type; 
}; 

template<> 
struct is_literal<char*> { 
    typedef std::string ptr_type; 
}; 

内的typedef type行为区分(const) char*enable_ifptr_typedisable_if

我们可以使用is_literal实施功能:

template<typename T> 
typename is_literal<T>::type 
toString(T& arg) 
{ 
    std::cout << "(literal)"; 
    // note the second argument which means length 
    // this can be a performance gain because no strlen call is needed 
    return std::string(arg, is_literal<T>::len); 
} 

template<typename T> 
typename is_literal<T>::ptr_type 
toString(T& arg) 
{ 
    std::cout << "(raw pointer)"; 
    return std::string(arg); 
} 

某些编译器可能有const问题 - 对于那些可能需要重载的const T& arg

我主要利用这款解决方案性能方面的原因,当我有频繁调用的函数,并要保存strlen来电或简单memcpy