C++: How to partially deduce template arguments from make_shared

拟墨画扇 提交于 2020-12-12 02:53:40

问题


In order to circumvent the restriction on partially supplied explicit template arguments, I embed the struct from which I want to deduce the class template parameters (Internal) into a second struct (Container).

I would like to enable the user of the code to create e.g. shared pointers of the resulting type. By writing my own create function within the struct, this works just fine.

#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>{});
}

But when I try to use make_shared directly, it fails. I would like to enable the user to use e.g. the std::make_shared function.

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

From what I understand, this fails because I cannot partially specify template arguments, and I am unable to deduce them from the make_shared function if I don't want to specify all template parameters.


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:

Is it possible to enable generator functions like std::make_shared to partially deduce template arguments like that? The entire code can be found here.


回答1:


If you create your own make_shared that accepts a template template parameter we can use decltype to deduce the resulting type and pass that on to 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)>);
}

The only issue here is that our make_shared needs to know the template signature of the expected target.

On the positive side we can add several overloads for different template signatures and we can use one parameter pack.



来源:https://stackoverflow.com/questions/59886167/c-how-to-partially-deduce-template-arguments-from-make-shared

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!