Я реализую универсальный класс, который должен вести себя по-разному для разных наборов типов (не только для разных дискретных типов). Цель состоит в том, чтобы сериализовать объекты разных типов, чтобы отправлять их по пользовательскому протоколу (но это скорее образовательная задача, чем что-то прагматическое; я студент, который интересуется распределенными вычислениями). Например, мне нужно по-разному отправлять числа с плавающей запятой и целые числа. Я также хочу иметь обработчик по умолчанию для других типов POD. Но мне нужно переопределить поведение для некоторых типов моих POD...
Я обнаружил, что метод SFINAE очень полезен и реализует общие классы для целочисленных типов и типов с плавающей запятой, для моих пользовательских типов с использованием принципа SFINAE и частичной специализации (см. код ниже). Но когда я попытался реализовать обработчик других типов POD, надеясь, что другие обработчики будут перекрывать более общий обработчик POD-типов, я столкнулся с проблемой неоднозначности. На самом деле нет никакого пересечения возможных специализаций моего класса GenericObject для типов POD и его подмножеств - целочисленных типов и типов с плавающей запятой.
Я пытался реализовать ручное упорядочивание специализаций, много читал о частичном упорядочивании, о том, что одна специализация предпочтительнее другой, если она более специализированная. Но мне не удалось решить проблему. У меня нет идей, как устранить неоднозначность моих частичных специализаций вручную.
Решение с исключением набора типов с плавающей запятой и целочисленных типов моего обработчика POD-типов для меня неприемлемо, т.к. таким образом получается лишняя зависимость между обработчиками. Я надеюсь, что есть правильный способ решить мою проблему. Например, при старте программы все статические ресурсы инициализируются с несколькими приоритетами. В GCC я могу управлять последовательностью такой инициализации с помощью конструктора атрибутов: __ attribute__((constructor(101))) или аналогичный атрибут init_priority. Я был бы рад, если бы я мог переупорядочить частичную специализацию шаблона таким образом.
Не могли бы вы предложить мне что-нибудь?
Вот мой код:
#include <type_traits>
#include <iostream>
#include <cxxabi.h>
// General form
template <typename T, typename Enable0 = void>
struct GenericObject {
char * description() {
return (char *)"Undefined";
}
};
// Specialization for integral types
template <typename T>
struct GenericObject<T, typename std::enable_if<std::is_integral<T>::value>::type> {
char * description() {
return (char *)"Integral";
}
};
// Specialization for real types
template <typename T>
struct GenericObject<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
char * description() {
return (char *)"Real";
}
};
// Specialization for other POD types. It MUST be less specialized than specializations for real and integral types, because in other way there will be an ambiguity, because every integral type is also a POD.
/*
HERE IS MY PROBLEM
*/
template <typename T>
struct GenericObject<T, typename std::enable_if<std::is_pod<T>::value>::type> {
char * description() {
return (char *)"POD";
}
};
// Declaration of types
struct IAmDefined {};
struct IAmUndefinedPOD {};
struct IAmUndefinedComplexClass : virtual IAmUndefinedPOD {};
// Specialization for IAmDefined class and also the most specialized template specialization.
template <>
struct GenericObject<IAmDefined> {
char * description() {
return (char *)"Defined";
}
};
// Produces nice output
std::string demangle(const char *raw) {
int status;
char *demangled = abi::__cxa_demangle(raw, 0, 0, &status);
std::string result(demangled);
free(demangled);
return result;
}
template <typename T>
void testObject() {
GenericObject<T> object;
std::cout << demangle(typeid(T).name()) << ": " << object.description() << std::endl;
}
int main() {
testObject<int>(); // Integral
testObject<long>(); // Integral
testObject<float>(); // Real
testObject<double>(); // Real
testObject<void>(); // POD
testObject<IAmDefined>(); // Defined
testObject<IAmUndefinedPOD>(); // POD
testObject<IAmUndefinedComplexClass>(); // Undefined
}
Вот ошибки времени компиляции:
g++ --std=c++11 main.cc -o specialization-of-sets
main.cc: In instantiation of 'void testObject() [with T = int]':
main.cc:85:21: required from here
main.cc:68:22: error: ambiguous class template instantiation for 'struct GenericObject<int, void>'
main.cc:15:8: error: candidates are: struct GenericObject<T, typename std::enable_if<std::is_integral<_Tp>::value>::type>
main.cc:36:8: error: struct GenericObject<T, typename std::enable_if<std::is_pod<_Tp>::value>::type>
main.cc:68:22: error: 'GenericObject<int, void> object' has incomplete type
main.cc: In instantiation of 'void testObject() [with T = long int]':
main.cc:86:22: required from here
main.cc:68:22: error: ambiguous class template instantiation for 'struct GenericObject<long int, void>'
main.cc:15:8: error: candidates are: struct GenericObject<T, typename std::enable_if<std::is_integral<_Tp>::value>::type>
main.cc:36:8: error: struct GenericObject<T, typename std::enable_if<std::is_pod<_Tp>::value>::type>
main.cc:68:22: error: 'GenericObject<long int, void> object' has incomplete type
main.cc: In instantiation of 'void testObject() [with T = float]':
main.cc:87:23: required from here
main.cc:68:22: error: ambiguous class template instantiation for 'struct GenericObject<float, void>'
main.cc:23:8: error: candidates are: struct GenericObject<T, typename std::enable_if<std::is_floating_point<_Tp>::value>::type>
main.cc:36:8: error: struct GenericObject<T, typename std::enable_if<std::is_pod<_Tp>::value>::type>
main.cc:68:22: error: 'GenericObject<float, void> object' has incomplete type
main.cc: In instantiation of 'void testObject() [with T = double]':
main.cc:88:24: required from here
main.cc:68:22: error: ambiguous class template instantiation for 'struct GenericObject<double, void>'
main.cc:23:8: error: candidates are: struct GenericObject<T, typename std::enable_if<std::is_floating_point<_Tp>::value>::type>
main.cc:36:8: error: struct GenericObject<T, typename std::enable_if<std::is_pod<_Tp>::value>::type>
main.cc:68:22: error: 'GenericObject<double, void> object' has incomplete type
Я использую GCC 4.8:
версия gcc 4.8.0 20120314 (экспериментальная) [версия магистрали 185382] (Ubuntu/Linaro 20120314-0ubuntu2)
Заранее спасибо.
char*
?! - person Xeo   schedule 27.10.2012!is_scalar
или что-то в этом роде. - person Kerrek SB   schedule 27.10.2012