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

时间:2017-09-11 00:07:34

标签: c++ c++11 operator-overloading c++14 argument-deduction

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

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

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;
}

它没有使用错误

进行编译
  

无法识别的模板声明/定义

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

2 个答案:

答案 0 :(得分:3)

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 {};

答案 1 :(得分:1)

你有一个不受欢迎的&gt;在您的代码中(关闭模板类型说明符)

试试这个:

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;
}