C++ 模板专门化帮助

C++ 模板专门化帮助,c++,templates,C++,Templates,我正在使用/学习模板函数专门化规则。我从这个函数开始 template<typename T> std::string toString(const T& t) { ostringstream out; out << t; return out.str(); } 模板 标准::字符串到字符串(常量T&T) { ostringstream out; 我认为这应该行得通: template <typename T> std

我正在使用/学习模板函数专门化规则。我从这个函数开始

template<typename T>
std::string toString(const T& t)
{
    ostringstream out;
    out << t;
    return out.str();
}
模板
标准::字符串到字符串(常量T&T)
{
ostringstream out;

我认为这应该行得通:

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

// non templated
std::string to_string(const char* x)
{
    ...
}
模板
std::字符串到_字符串(常量T&)
{
...
}
//非模板
std::字符串到_字符串(常量字符*x)
{
...
}

为什么要专门化?只需重载函数。通常不需要完全专门化函数模板

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

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

您可以省略专业化
S2
,然后
“There”
”,Bob“
将使用
S3


请注意,实际上,这根本不是专门化。我通过创建新的函数模板进行了欺骗。但我必须将
size\u t
参数输入;如果您为
N
选择一个值并将其作为具体类型的一部分写入函数签名中,您只能在这里进行真正的专门化,或者,如果您可以部分专门化函数模板。

它不起作用的原因是它实际上不是正确的类型。字符串文字不是
const char*
类型,它们是
const char[N]
类型。当您传递字符串文字时,t被推断为
char[N]。这是一个精确匹配,而不是专门化。不能为字符串文字设置特殊化,因为这需要一个部分规范,C++不支持部分函数特化。

< P>我和SunStudio C++编译器有类似的问题。

首先,我使用了两个数组重载(
char(&)[N]
带和不带
const
)和两个指针重载(
char*
const char*

令我惊讶的是,像
toString(“quoted literal”)
这样的调用使用了
const char*
,而且似乎不可能强制编译器选择数组重载。更有趣的是,对于
char lit[]=“literal”
这样的参数,
toString(lit)
选择了数组重载

经过一番思考,我找到了一种方法,使代码表现为部分函数专门化

首先,定义一个模板来区分
(const)char*
(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;
};
某些编译器可能在
const
方面存在问题-对于那些
const T&arg
可能需要重载


当我经常调用函数并希望保存
strlen
调用或用simple
memcpy
替换
strcpy
调用时,我使用此解决方案主要是出于性能原因。是的,它会起作用,但我想研究模板专门化。我知道,这是一种人为的情况。因此我想您可能需要专门化一次是conchchar *,一次是char *。因为char不是const char *,我猜C++不匹配专业化,使用更通用的函数。如果你想要const char *和char *使用相同的专门化,我想你必须把Car参数从Cch*到const char *。emplate专门化是指函数模板专门化很少有帮助。传递字符串文字后,它将推断为与指针类型不匹配的数组类型(这是专门化,因此类型必须完全匹配)。对于您显示的重载,它将使用第二个
toString
,因为转换序列将是不明确的,但第二个是非模板的,因此获胜。@Tomalak:我理解正确了吗:您在
T
之后编写
const
(第一个模板函数
std::string toString(T const&T)
),在T是指针的情况下,使参考常数成为常数?@Christian:没错。对于专门化,参数必须匹配;因此我为
T
选择
char-const*
,结果是
char-const*const&
,表示有效的专门化。
template <typename T>
std::string toString(const T& in)
{
    ostringstream out;
    out << in;
    return out.str();
}

std::string toString(char const* in)
{
    return in;
}
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
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;
};
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);
}