首页 > 解决方案 > 如何检查模板类型参数是字符类型还是字符串类型?

问题描述

我正在尝试编写能够区分字符类型(char,wchar_t等)、字符串类型(std::string、std::wstring 等)和数字类型的代码,因此我可以将字符包含在单个- 引号和双引号中的字符串。这个想法是根据它们的输出方式来区别对待值。字符和字符串从根本上不同于数值,因为它们根据其内容的编码表示(即 ASCII、Unicode、UTF 等)而不是数值来显示。

(注意:这段代码是从一个更大更复杂的程序中提取的)

这是我的代码,用

g++ -std=c++14 testchar.cpp -o testchar

在使用 g++ v5.4.0 编译的 Linux Mint 18.3 (Sylvia) 下工作

#include <iostream>
#include <locale>
#include <codecvt>
#include <string>
#include <type_traits>

using std::cout;
using std::is_same;
using std::string;
using std::u16string;
using std::u32string;
using std::wstring;

#define is_string_type(T)  ( is_same<T,string>::value    || is_same<T,wstring>::value   || \
                             is_same<T,u16string>::value || is_same<T,u32string>::value )
#define is_char_type(T)    ( is_same<T,char>::value      || is_same<T,wchar_t>::value   || \
                             is_same<T,char16_t>::value  || is_same<T,char32_t>::value  )
#define is_numeric_type(T) ( !is_char_type(T) && std::is_arithmetic<T>::value )

template <typename T>
typename std::enable_if<is_string_type(T),void>::type
output_value( const string& name, const T& strval ) {
    cout << "String " << name << " is \"" << strval << "\";\n";
}
template <typename T>
typename std::enable_if<is_char_type(T),void>::type
output_value( const string& name, const T& chrval ) {
    cout << "Character " << name << " is '" << chrval << "';\n";
}
template <typename T>
typename std::enable_if<is_numeric_type(T),void>::type
output_value( const string& name, const T& val ) {
    cout << "Numeric " << name << " is " << val << ";\n";
}

int main(void)
{
    string    name;
    short     sval = 4321;
    int       ival = 123;
    long      lval = 1234567890L;
    char      cval = 'W';
    string    Sval = "string";

    name = "sval";
    output_value( name, sval );
    name = "ival";
    output_value( name, ival );
    name = "lval";
    output_value( name, lval );
    name = "cval";
    output_value( name, cval );
    name = "strval";
    output_value( name, Sval );

    return 0;
}

但是我的宏,'is_char_type' 和 'is_string_type' 是丑陋的,不是很健壮。他们是宏......糟糕!我确实尝试使用std::is_base_of<std::basic_string,T>::value'is_string_type',但编译器抛出了一个错误:

testchar.cpp:17:65: error: type/value mismatch at argument 1 in template parameter list for ‘template<class, class> struct std::is_base_of’

如果有人知道更好的方法,请告诉我!我有点惊讶这些 (is_character_typeis_string_type) 不存在于type_traits......或者它们可能存在,但被巧妙地伪装了?

标签: c++templatescharc++14wchar-t

解决方案


template<class T>struct tag_t{};
template<class T>constexpr tag_t<T> tag{};
namespace detect_string {
  template<class T, class...Ts>
  constexpr bool is_stringlike(tag_t<T>, Ts&&...){ return false; }
  template<class T, class A>
  constexpr bool is_stringlike( tag_t<std::basic_string<T,A>> ){ return true; }
  template<class T>
  constexpr bool detect=is_stringlike(tag<T>); // enable ADL extension
}
namespace detect_character {
  template<class T, class...Ts>
  constexpr bool is_charlike(tag_t<T>, Ts&&...){ return false; }
  constexpr bool is_charlike( tag_t<char> ){ return true; }
  constexpr bool is_charlike( tag_t<wchar_t> ){ return true; }
  // ETC
  template<class T>
  constexpr bool detect=is_charlike(tag<T>); // enable ADL extension
}

现在detect_character::detect<char>就是true这样detect_string::detect<std::wstring>

如果您只想将 charlikes 字符串作为字符串,请将其添加到is_stringlike重载中。

你可以通过在类型 X 的命名空间中定义一个is_stringlike(tag_t<X>)重载来扩展其中的任何一个,它会被自动找到。或者在detect_stringlike. 您不能以std这种方式添加重载,因此请在detect_stringlike命名空间中添加它们。

还有其他解决方案,但这是唯一避免单一中央列表脆弱性的解决方案。


推荐阅读