c++ - 如何检查模板类型参数是字符类型还是字符串类型?
问题描述
我正在尝试编写能够区分字符类型(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_type
和is_string_type
) 不存在于type_traits
......或者它们可能存在,但被巧妙地伪装了?
解决方案
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
命名空间中添加它们。
还有其他解决方案,但这是唯一避免单一中央列表脆弱性的解决方案。
推荐阅读
- css - 如何在 Angular 7 中获取组件的 CSS 文件内容?
- asp.net - 无法在 Visual Studio Code 中初始化 MVC 模板
- kubernetes - kubectl 无法在本地使用 minikube 检测 localhost:8080
- python - 如何根据 pd.DataFrame 值创建 f 字符串(类似)列表?
- javascript - 如何在警报消息上设置超时?
- node.js - 将项目部署到数字海洋后,单击登录或注册按钮时会引发此错误
- sql - 从 XML 文档中获取数据到 SQL 表中,使用 OPENROWSET 从 XML 中检索属性时为空表
- python - 如何设置列中的所有值 = 0,其中选择列中的值重复,同时保持第一个重复值不变
- sapui5 - 如何在项目模板中添加 IconTabSeparator?
- c# - 将文本框作为参数从 Xaml 传递到单击按钮事件