C ++: как частично вывести аргументы шаблона из make_shared - PullRequest
1 голос
/ 23 января 2020

Чтобы обойти ограничение на частично предоставленные явные аргументы шаблона , я встраиваю структуру, из которой я хочу вывести параметры шаблона класса (Internal), во вторую структуру (Container) .

Я хотел бы разрешить пользователю кода создавать, например, общие указатели результирующего типа. Написав мою собственную create функцию в структуре, это прекрасно работает.

#include <memory>

/// Container that is used in order to partially specify template arguments
template <int A> struct Container {

  /// Contained type, of which the template arguments are deduced.
  template <int B> struct Internal {
    explicit Internal(std::integral_constant<int, B> fu) { (void)fu; }
  };

  /// Helper function
  template <int C>
  [[nodiscard]] static auto create(std::integral_constant<int, C> t) noexcept {
    return std::make_shared<Container<A>::Internal<C>>(t);
  }
};


int main() {
  Container<1>::Internal works{std::integral_constant<int, 8>{}};
  auto const worksAswell = Container<1>::create(std::integral_constant<int, 8>{});
}

Но когда я пытаюсь использовать make_shared напрямую, это не удается. Я хотел бы позволить пользователю использовать, например, функцию std :: make_shared.

int main() {
  auto const fails = std::make_shared<Container<1>::Internal>(std::integral_constant<int, 8>{}); 
}

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


main.cc: In function ‘int main()’:
main.cc:21:74: error: no matching function for call to ‘make_shared<1>(std::integral_constant<int, 8>)’
   21 |   auto const fails = std::make_shared<1>(std::integral_constant<int, 8>{});
      |                                                                          ^
In file included from /usr/include/c++/9.2.0/memory:81,
                 from /home/juli/main9.cc:1:
/usr/include/c++/9.2.0/bits/shared_ptr.h:714:5: note: candidate: ‘template<class _Tp, class ... _Args> std::shared_ptr<_Tp> std::make_shared(_Args&& ...)’
  714 |     make_shared(_Args&&... __args)
      |     ^~~~~~~~~~~
/usr/include/c++/9.2.0/bits/shared_ptr.h:714:5: note:   template argument deduction/substitution failed:

Можно ли разрешить функциям генератора, таким как std::make_shared, частично выводить аргументы шаблона, подобные этому? Весь код можно найти здесь .

1 Ответ

2 голосов
/ 23 января 2020

Если вы создаете свой собственный make_shared, который принимает параметр шаблона шаблона, мы можем использовать decltype для вывода результирующего типа и передачи его на std::make_shared.

#include <memory>
#include <type_traits>

/// Container that is used in order to partially specify template arguments
template <int A> struct Container {

  /// Contained type, of which the template arguments are deduced.
  template <int B> struct Internal {
    explicit Internal(std::integral_constant<int, B> fu) { (void)fu; }
  };
};

template <template <int> typename partial, typename... Args>
auto make_shared(Args&&... args) {
    using target_type = std::remove_pointer_t<decltype(new partial{std::declval<Args>()...})>;
    return std::make_shared<target_type>(std::forward<Args>(args)...);
}

using std::make_shared;

int main() {
  auto const fails = make_shared<Container<1>::Internal>(std::integral_constant<int, 8>{});
  static_assert(std::is_same_v<const std::shared_ptr<Container<1>::Internal<8>>, decltype(fails)>);
}

Единственная проблема здесь в том, что нашему make_shared нужно знать сигнатуру шаблона ожидаемой цели.

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

...