2015-07-18 2 views
3

У меня есть класс черты, которые, как предполагается предоставить только одну информацию о других типах (в виде строки):Какой самый дешевый способ специализироваться члена черты

template<typename T> 
struct some_traits { 
    static const char* const some_string; 
}; 

Мне нужно предусмотреть специальные экземпляры some_string для каждого типа. Распространенный способ я знаю, как сделать это только объявить some_traits, а затем написать специализации:

template<typename T> 
struct some_traits; 

template<> 
struct some_traits<blah> { 
    static const char* const some_string; 
}; 
const char* const some_traits<blah>::some_string = "blah string"; 

Это, однако, много кода, когда все, что мне нужно, это специализированная some_string. Есть ли способ упростить это?

Я пытался возиться с явными специализациями, но не смог придумать синтаксис, который не заставил компилятор высказывать ядовитые сообщения об ошибках.

Примечания:

  • Я знаю, что могу скрыть это за макросом. Мне все еще интересно.
  • Необходимо выполнить компиляцию на встроенной платформе с помощью GCC 4.1. Итак, C++ 03 - это все, что у нас есть. (Boost в порядке, но для ограниченной поддержки Posix мы застряли с 1.52, если это имеет значение.)
+0

Вам нужны только полные специализации? http://coliru.stacked-crooked.com/a/d47849e14289149b – dyp

+0

сколько специализаций вам нужно? –

+0

@ dyp: Да, это было бы так. Я думал, вы не можете специализировать членов шаблона шаблона? – sbi

ответ

7

можно явно специализироваться членов шаблонов классов:

template<typename T> 
struct some_traits { 
    static const char* const some_string; 
}; 

template<> 
char const* const some_traits<int>::some_string = "int"; 

Это должно уменьшить накладные расходы на несколько декларирование новых специализаций. Однако этот метод не может быть применен к частичным специализациям:

template<typename T> struct foo {}; 
template<typename T> 
char const* const some_traits<foo<T>>::some_string = "foo<T>"; // error 

... то есть, если вы не добавите частичной специализации для some_traits:

template<typename T> 
struct some_traits<foo<T>> { 
    char const* const some_string; 
}; 

Два варианта:

(1) Использование ADL и функций

template<typename T> struct some_string_tag {}; 

template<typename T> 
struct some_traits { 
    static const char* const some_string; 
}; 
template<typename T> 
char const* const some_traits<T>::some_string = get_string(some_string_tag<T>()); 

специализация может быть записана как:

char const* get_string(some_string_tag<int>) { return "int"; } 

и частичные специализации, как:

template<typename T> 
char const* get_string(some_string_tag<foo<T>>) { return "foo<T>"; } 

(В этом случае some_traits точка для настройки, как найдена строка, и она обеспечивает удобный доступ к строке в качестве переменной.)

(2) Вторая черта, используя функцию встроенного

template<typename T> 
char const* const some_traits<T>::some_string = some_traits_X<T>::get_string(); 

template<typename T> struct some_traits_X { 
    // provide: static char const* get_string(); 
}; 

template<> 
struct some_traits_X<int> { 
    static char const* get_string() { return "int"; } 
}; 

template<typename T> 
struct some_traits_X<foo<T>> { 
    static char const* get_string() { return "foo<T>"; } 
}; 
+0

Я обнаружил, что, как правило, константы более универсальны, чем вызовы функций (см. 'Std :: numeric_limits <> :: макс() '). Вполне возможно, что со строками это не делает такой большой разницы, но я хотел бы знать, как это сделать в любом случае. – sbi

+0

@sbi Это означалось как второй признак, просто чтобы обеспечить строку. Вы все еще можете использовать свой первоначальный признак как «адаптер». См. Мой обновленный ответ. Это может быть более удобно, если у вас есть несколько черт, которые все требуют специализации. – dyp

+0

Я вижу. Довольно всеобъемлющий, этот ответ. Спасибо! – sbi

-1

Почему бы не использовать функции?

template<typename T> 
struct some_traits { 
    static const char* const some_string(); 
}; 

template<> 
struct some_traits<blah> { 
    static const char* const some_string() { return "blah string"; } 
}; 
+0

Поскольку константа, в общем, более универсальна, чем вызов функции? (BTW, если бы я сделал это, я бы только _declare_ первичный шаблон и не стал бы _define_ it.) – sbi

Смежные вопросы