Компактный способ вывести дополнительные типы параметров шаблона для аргументов шаблона указателя на член.

Примечание: этот вопрос в значительной степени академический.

Мы можем использовать указатель на член в качестве параметра шаблона в шаблоне класса, но если «зависимые» типы неизвестны, мы должны объявить их все как параметры шаблона. Например:

// 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;
}

Но это не похоже на проблему, для решения которой нужны макросы препроцессора.


person cheshirekow    schedule 01.11.2019    source источник
comment
если С++ 17 нет рядом. Первое решение кажется более компактным и обеспечивает хорошую читаемость аргументов шаблона, чем второе решение.   -  person luck    schedule 01.11.2019


Ответы (1)


Аналогичный вопрос: Вывод аргументов шаблона указателя на элемент

Ответ оттуда — опираться на автомагию С++ 17:

template <auto p>
struct Foo {};
person parktomatomi    schedule 01.11.2019