Если возможно, я бы хотел сделать это в целом (одна специализация, если у нее есть .details, другая, если у нее есть .other_info и т. Д.).
Если я получил ваши ожидания, вы можете использовать трюк choice
в сочетании с decltype
, как это происходит в следующем примере:
#include <iostream>
template<int N>
struct choice: choice<N-1> {};
template<>
struct choice<0> {};
struct Foo { int error; };
struct Bar { int error; int details; };
struct Quux { int error; char other_info; };
template<typename MSG>
auto reportErr(choice<2>, const MSG& msg) -> decltype(msg.details, void()) {
std::cout << "ERROR: " << msg.error;
std::cout << ", details: " << msg.details << std::endl;
}
template<typename MSG>
auto reportErr(choice<1>, const MSG& msg) -> decltype(msg.other_info, void()) {
std::cout << "ERROR: " << msg.error;
std::cout << ", other_info: " << msg.other_info << std::endl;
}
template <typename MSG>
void reportErr(choice<0>, const MSG& msg) {
std::cout << "ERROR: " << msg.error << std::endl;
}
template <typename MSG>
void reportErr(const MSG &msg) {
reportErr(choice<100>{}, msg);
}
int main() {
reportErr(Foo{0});
reportErr(Bar{0, 42});
reportErr(Quux{0, 'c'});
}
Посмотрите и запустите wandbox
(на самом деле, используя GCC 4.5.4, упомянутая вами версия недоступна). Он использует разрешение перегрузки для выбора рабочей версии функции в соответствии с типом сообщения и отбрасывает все, что находится между ними. Вы можете добавить больше специализаций (назовем их так, даже если они не являются правильными специализациями в конце концов) и отсортировать их в соответствии с вашими предпочтениями, скорректировав параметр choice
при необходимости ( чем выше его значение, тем выше приоритет специализации ).
Нечто подобное можно также сделать, комбинируя трюк choice
с sizeof
в решении на основе SFINAE, аналогичном тому, что я показал выше.
В частности, вот рабочий пример:
#include <iostream>
template<int N>
struct choice: choice<N-1> {};
template<>
struct choice<0> {};
struct Foo { int error; };
struct Bar { int error; int details; };
struct Quux { int error; char other_info; };
template<typename MSG, std::size_t = sizeof(MSG::details)>
void reportErr(choice<2>, const MSG& msg) {
std::cout << "ERROR: " << msg.error;
std::cout << ", details: " << msg.details << std::endl;
}
template<typename MSG, std::size_t = sizeof(MSG::other_info)>
void reportErr(choice<1>, const MSG& msg) {
std::cout << "ERROR: " << msg.error;
std::cout << ", other_info: " << msg.other_info << std::endl;
}
template <typename MSG>
void reportErr(choice<0>, const MSG& msg) {
std::cout << "ERROR: " << msg.error << std::endl;
}
template <typename MSG>
void reportErr(const MSG &msg) {
reportErr(choice<100>{}, msg);
}
int main() {
reportErr(Foo{0});
reportErr(Bar{0, 42});
reportErr(Quux{0, 'c'});
}
Посмотреть и запустить на wandbox
. Преимущество состоит в том, что это решение не страдает от раздражающего предупреждения, которое вы получаете с предыдущим.
Я протестировал его с более старым компилятором, чем вы просили (GCC 4.5.4), поэтому я вполне уверен, что они оба работают также с GCC 4.6.x.