Было бы неплохо получить более подробное объяснение того, почему «время компиляции важно» (помогает предлагать альтернативы). Но, на мой взгляд, все, что вам нужно для выполнения компиляции с указателем на член, на самом деле может сделать. Мой вариант - предложение Томаса, смешанное с некоторой философией C ++. Сначала давайте определим:
template <typename T, T v>
struct val
{};
этот шаблон структуры может эффективно служить значением времени компиляции, и вам не нужно "static value = v;", чтобы использовать его либо во время компиляции, либо во время выполнения. Рассмотрим:
template <int n>
struct Foo
{
//something dependent on n
};
и
template <typename T>
struct Bar;
template <int n>
struct Bar <val <int, n> >
{
//something dependent of n
};
Foo и Bar функционально эквивалентны, каждый шаблон мета-кадабры, который может быть выполнен с помощью Foo, также может быть выполнен с помощью Bar (просто передайте val вместо n). То же самое, что вы можете упаковать указатель на член в val <>:
val <typeof (&My::a), &My::a>
эти значения времени компиляции теперь могут храниться в списках типов (например, boost :: mpl :: кое-что), сравниваться, преобразовываться и т. Д. Во все время компиляции. И когда вы, наконец, захотите использовать их как указатель на член во время выполнения, просто определите один шаблон функции:
template <typename T, T value>
T
extract (val <T, value>)
{
return value;
}
и используйте его:
typedef val <typeof (A::i), A::i> a_i;
A a;
std::cout << (a .* extract (a_i ()));
P.S .: Есть некоторые неуклюжие конструкции об этом решении, но все это ради простоты и объяснения. Например, довольно некрасиво (a. * Extract (a_i ())) можно упростить, обернув его во что-то более специфичное для указателя на член:
template <typename M, typename C>
typename mem_type <M>::value &
mem_apply (C &c)
{
M m;
return c .* extract (m);
}
где mem_type - шаблон класса, который извлекает тип члена, на который ссылается M. Тогда использование будет:
std::cout << mem_apply <a_i> (a);