std::enable_if_t 将字符串与非字符串函数参数分开

std::enable_if_t to separate string from non string function parameters

我需要在双引号内打印所有类型的字符串数据,而其他不带双引号的。

这是我检查参数是否为字符串的函数。

template<class T>
struct is_str : std::integral_constant<bool, false> {};
template<> struct is_str<char*> : std::integral_constant<bool, true> {};
template<> struct is_str<wchar_t*> : std::integral_constant<bool, true> {};
template<> struct is_str<const char*> : std::integral_constant<bool, true> {};
template<> struct is_str<const wchar_t*> : std::integral_constant<bool, true> {};
template<> struct is_str<std::string> : std::integral_constant<bool, true> {};
template<> struct is_str<const std::string> : std::integral_constant<bool, true> {};
template<> struct is_str<std::wstring> : std::integral_constant<bool, true> {};
template<> struct is_str<const std::wstring> : std::integral_constant<bool, true> {};

而在打印机功能中,我是这样使用上述功能的

template<typename T>
std::enable_if_t<is_str<T>::value>, std::ostream&>
    operator<<(std::ostream& xx, const T& ar)
{
    xx << "\"" << ar << "\"";
    return xx;
}

template<typename T>
std::enable_if_t<!is_str<T>::value>, std::ostream&>
    operator<<(std::ostream& xx, const T& ar)
{
    xx << ar;
    return xx;
}

它没有编译错误

unrecognized template declaration/definition

有人可以告诉我如何解决这个问题或处理这种情况的更好方法吗?

您的代码中有一个不需要的 >(关闭模板类型说明符)

试试这个:

template<class T>
struct is_str : std::integral_constant<bool, false> {};
template<> struct is_str<char*> : std::integral_constant<bool, true> {};
template<> struct is_str<wchar_t*> : std::integral_constant<bool, true> {};
template<> struct is_str<const char*> : std::integral_constant<bool, true> {};
template<> struct is_str<const wchar_t*> : std::integral_constant<bool, true> {};
template<> struct is_str<std::string> : std::integral_constant<bool, true> {};
template<> struct is_str<const std::string> : std::integral_constant<bool, true> {};
template<> struct is_str<std::wstring> : std::integral_constant<bool, true> {};
template<> struct is_str<const std::wstring> : std::integral_constant<bool, true> {};

template<typename T>
std::enable_if_t<is_str<T>::value, std::ostream&> /* fixed line versus yours */
operator<<(std::ostream& xx, const T& ar) 
{
    xx << "\"" << ar << "\"";
    return xx;
}

template<typename T>
std::enable_if_t<!is_str<T>::value, std::ostream&> /* fixed line versus yours */
operator<<(std::ostream& xx, const T& ar)
{
    xx << ar;
    return xx;
}

Graham Best 是对的,但还有另一个(更大的,恕我直言)问题。

你没有定义operator<<;你正在重新定义它调用自己。

据我所知,这是不可能的(你重新定义一个函数,编译器不知道调用哪个版本)并且当你写的时候(在重新定义的运算符内部)

xx << "\"" << ar << "\"";

应该使用哪个版本的operator<<()?重新定义新的(导致循环递归)还是旧的?

我认为退出此问题的最佳方法是避免重新定义 operator<<() 并定义一个简单的函数;例如,以下 print()

template<typename T>
std::enable_if_t<is_str<T>::value, std::string> print (T const & ar)
 {
   std::ostringstream oss;

   oss << "\"" << ar << "\"";

   return oss.str();
 }

template<typename T>
std::enable_if_t<!is_str<T>::value, T const &> print (T const & ar)
 { return ar; }

然后这样使用

std::cout << print(std::string{"abc"}) << std::endl; // add quotes
std::cout << print(1) << std::endl;                  // no quotes

En passant:有几个 类 可用于编写更紧凑的代码:std::true_type,定义为 std::integral_constant<bool, true>,和 std::false_type,定义为 std::integral_constant<bool, false>.

所以你可以定义is_str如下

template<class T>
struct is_str : std::false_type {};

template<> struct is_str<char*> : std::true_type {};
template<> struct is_str<wchar_t*> : std::true_type {};
// ...

OBSERVE 如果你写

std::cout << print("abc") << std::endl; // add quotes

print() 没有添加引号。

这是因为 "abc" 不是 char const *;这是 const char[4].

因此,如果您也想将引号添加到 char[N]wchar_t[N],则应添加以下特化项

template<std::size_t N> struct is_str<char[N]> : std::true_type {};
template<std::size_t N> struct is_str<wchar_t[N]> : std::true_type {};