Как я могу проверить, является ли параметр типа шаблона типом символа или типом строки? - PullRequest
0 голосов
/ 02 июля 2018

Я пытаюсь написать код, который сможет различать типы символов (char, wchar_t и т. Д.), Строковые типы (std :: string, std :: wstring и т. Д.) И числовые типы, так что я могу заключать символы в одинарные кавычки и строки в двойные кавычки. Идея состоит в том, чтобы обрабатывать значения по-разному в зависимости от того, как они выводятся. Символы и строки принципиально отличаются от числовых значений, потому что они отображаются в соответствии с представлением кодирования их содержимого (т. Е. ASCII, Unicode, UTF и т. Д.), А не в виде числовых значений.

(Примечание: этот код извлечен из гораздо более сложной и сложной программы)

Вот мой код, скомпилированный с

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

, работающий под Linux Mint 18.3 (Sylvia), скомпилированный с g ++ v5.4.0

#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 ... или, может быть, они существуют, но умно замаскированы?

1 Ответ

0 голосов
/ 02 июля 2018
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>.

Если вы хотите, чтобы строками были только строки чарликов, добавьте их к перегрузке is_stringlike.

Вы можете расширить любой из них, определив в пространстве имен типа X a is_stringlike(tag_t<X>) перегрузку, и он будет найден автоматически. Или сделать это в detect_stringlike. Вы не можете добавлять перегрузки к std таким образом, поэтому делайте это в пространстве имен detect_stringlike.

Существуют и другие решения, но это единственное, которое позволяет избежать хрупкости единого центрального списка.

...