Примечание: этот вопрос носит в основном академический характер.
Мы можем использовать указатель на член в качестве параметра шаблона в шаблоне класса, но если «зависимые» типы не известны, мы должны объявить всеих как параметры шаблона. Например:
// Our template operates with a "pointer to member", but it's generic for
// both the type of the member value itself, as well as the owner type of
// which the value is a member.
template <class T, class V, V T::*memptr>
struct Foo {};
В этом случае мы должны включить T
, V
в качестве параметров шаблона, если функциональность шаблона является общей для этих типов. Однако использование этого шаблона выглядит довольно многословно:
struct Bar {int a;};
struct Baz {double a;};
int main(int argc, char** argv) {
// The first two parameters "Bar, int" are kinda redundant
Foo<Bar, int, &Bar::a> foo1;
// Same here with Baz, double
Foo<Baz, double, &Baz::a> foo2;
}
В частности, параметр шаблона &Bar::a
является параметром не типового типа, тип которого int &Bar::*
. Таким образом, кажется, что T=Bar, V=int
вполне очевидно.
Существует ли синтаксис, метапрограмма или конструкция, которую можно использовать, чтобы мы могли создать экземпляр шаблона только с memptr=&Bar::a
и позволить выводить / выводить T=Bar, V=int
?
В идеале мы должны создать экземпляр шаблона просто:
Foo<&Bar::a> foo1;
Foo<&Baz::a> foo2;
Но я не могу придумать, как этого добиться. У меня есть решение, которое использует макрос препроцессора:
// This is an ugly metaprogram and macro to shorten-up usages of the template
template <class T, class V>
struct Step2 {
template <V T::*memptr>
struct Step3 {
typedef Foo<T, V, memptr> Type;
};
};
template <class T, class V>
Step2<T, V> step1(V T::*memptr);
#define FOO(T, MEMBER) decltype(step1(&T::MEMBER))::Step3<&T::MEMBER>::Type
, который можно использовать как:
int main(int argc, char** argv) {
// It seems that thre should be a more compact way to instantiate this
// template. Indeed the macro does this, but macros are tough because they're
// global names and it can make compiler errors really tough to comprehend.
FOO(Bar, a) foo1;
FOO(Baz, a) foo2;
}
Но это не похоже на проблему, которая требует макросов препроцессора в качестве решения.