Компактный способ вывода дополнительных типов параметров шаблона для аргументов шаблона указатель на член - PullRequest
0 голосов
/ 01 ноября 2019

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

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

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

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

1 Ответ

1 голос
/ 01 ноября 2019

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

Ответ от этого заключается в использовании магии C ++ 17 auto:

template <auto p>
struct Foo {};
...