如何检查模板类型参数是字符类型还是字符串类型?

时间:2018-07-02 03:20:21

标签: c++ templates char c++14 wchar-t

我正在尝试编写能够区分字符类型(charwchar_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'很丑陋,而且不够健壮。而且它们是宏......!我确实尝试对{is_string_type'使用std::is_base_of<std::basic_string,T>::value,但是编译器抛出错误:

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中不存在,或者它们确实存在,但被巧妙地伪装了,我感到有些惊讶?

2 个答案:

答案 0 :(得分:2)

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名称空间中这样做。

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

答案 1 :(得分:0)

遵循 std 模板库中的模式,您可以编写如下助手:

// Given `std::` namespace ...
template <bool _Val>
using bool_constant = integral_constant<bool, _Val>;

// EdgeS AfBox `pal::` namespace - platform-abstraction-layer type support
// Char8, UChar8, SChar8, UChar16t, WChar16, UChar16, UChar32
typedef char8_t                         UChar8t;
typedef unsigned char                   UChar8;
typedef signed char                     SChar8;
typedef char                             Char8;
// ..other defn's elided..

// EdgeS AfBox `pal::` namespace - platform-abstraction-layer type support
template<typename T>
constexpr bool is_char_type_v = std::_Is_any_of_v<std::remove_cv_t<T>,
  Char8, UChar8, SChar8, UChar16t, WChar16, UChar16, UChar32>;
template<typename T>
struct is_char_type : std::bool_constant <is_char_type_v<T>> {};

// Use it as follows:
template<typename char_ta,
  typename std::enable_if<pal::is_char_type<char_ta>::value>::type* = nullptr>
void populate_arg(AfBlob&& bArgs, char_ta* z) {
  //..ellided..
}