我正在尝试编写能够区分字符类型(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'很丑陋,而且不够健壮。而且它们是宏......!我确实尝试对{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_type
和is_string_type
)在type_traits
中不存在,或者它们确实存在,但被巧妙地伪装了,我感到有些惊讶?
答案 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..
}