Неопределенная ссылка на специализированный элемент шаблона - PullRequest
0 голосов
/ 27 августа 2018

У меня есть класс, параметризованный классом шаблона шаблона со статической функцией-членом:

template <template <typename> class F>
struct A {
  static int foo();
};

Этот класс не имеет определения по умолчанию для foo и должен быть специализированным для различных типов.

У меня также есть другой класс, параметризованный классом шаблона шаблона с вложенным классом шаблона:

template <template <typename> class F>
struct B {
  template <typename T>
  struct C {};
};

Я хочу, чтобы C специализировался A для любого шаблона шаблона класса F, который уже специализируется A:

template <template <typename> class F>
struct A<B<F>::template C> {
  static int foo();
};

template <template <typename> class F>
int A<B<F>::template C>::foo() {
  return A<F>::foo() / 2;
}

Итак, если у меня есть класс, который специализируется A:

template <typename T>
struct E {};

template <>
int A<E>::foo() {
  return 42;
}

Я ожидал бы, что смогу использовать такую ​​специализацию, как эта (и возвращаю 21):

int bar() {
  return A<B<E>::template C>::foo();
}

Однако ссылка не устанавливается - не удается найти ссылку на A<B<E>::C>::foo().

(Обратите внимание, что все это в одном файле - здесь нет ничего странного с заголовками)

Похоже, что компилятор пытается использовать основной шаблон для A, а не для специализации, что означает, что foo не определено. Почему он не использует специализацию в этом случае?

Полный пример

template <template <typename> class F>
struct A {
  static int foo();
};

template <template <typename> class F>
struct B {
  template <typename T>
  struct C {};
};

template <template <typename> class F>
struct A<B<F>::template C> {
  static int foo();
};

template <template <typename> class F>
int A<B<F>::template C>::foo() {
  return A<F>::foo() / 2;
}

template <typename T>
struct E {};

template <>
int A<E>::foo() {
  return 42;
}

int bar() {
  // Link fails - error: undefined reference to 'A<B<E>::C>::foo()'
  return A<B<E>::template C>::foo();
}

1 Ответ

0 голосов
/ 27 августа 2018
template<class T>
struct A {};

template<class T>
struct B {
  using type=T;
};

template<class T>
struct A<typename B<T>::type> {};

это в основном то же самое, но с одним меньшим количеством шаблонов.

Это тоже не работает.

Проблема в том, что B<T>::type или B<T>::template Z или что-то еще, в общем случае, является произвольной функцией времени компиляции.

И чтобы сопоставить шаблон с ним, нам нужно инвертировать эту произвольную функцию времени компиляции.

Стандарт гласит: «Компиляторы не должны этого делать», что является одной из немногих вменяемых вещей, которые вы можете сделать здесь. Это определенно говорит это для типов; Что касается шаблонов, то в стандартной формулировке параметров шаблонов часто отсутствуют детали, поэтому я не удивлюсь, если эта формулировка будет отсутствовать. Но если этого не произойдет, это будет ошибка в стандарте.

Чтобы перейти с

template<class T>
struct A<typename B<T>::type> {};

, чтобы увидеть, соответствует ли A<foo>, необходимо проверить все типы T, чтобы увидеть, какой из них имеет B<T>::type, равный foo.

Возможно, это не то, что вы намереваетесь попросить, но это то, о чем вы просите.

То же самое относится и к вашему примеру шаблона.

template <template <typename> class F>
struct A<B<F>::template C> {
  static int foo();
};

вы просите, чтобы компилятор проверил каждый тип F, так что если вы передадите его произвольному шаблону B<>, а затем оцените ::C, соответствует ли шаблон тому, что вы передаете A.

Первый забавный кейс:

template<class X>
struct C0 {};
template <template <typename> class F>
struct B {
  template <typename T>
  using C=C0<X>:
};

Теперь, что такое F в A<C0>? Каждый F квалифицируется.

template<class X>
struct C0 {};
template <template <typename> class F, class=void>
struct B {
  template <typename T>
  using C=C0<X>:
};
template<class X>
struct C1 {};
template <template <typename> class F, class=void>
struct B<
  F,
  std::enable_if_t<
    proves_collatz_conjecture( F<int>::value )
  >
> {
  template <typename T>
  using C=C1<T>;
};

теперь для паттерна mach A<C0> компилятор должен создать F таким образом, чтобы F<int>::value был типом времени компиляции, который при передаче в proves_collatz_conjecture возвращает true во время компиляции.

Это было бы полезно.


специализация шаблона - сопоставление с шаблоном. В C ++ вы не можете сопоставлять шаблоны с зависимыми типами (и, вероятно, с шаблонами), поскольку ни у типов, ни у шаблонов нет идентификатора, превышающего их значение.

Вы не можете проверить область, в которой определена переменная, тип или шаблон. Поэтому вы не можете сопоставить шаблон с этим.

Если вы хотите делать то, что хотите, шаблон C должен иметь свойство, которое вы можете проверить и проверить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...